diff --git a/03concurrency/0301/src/main/java/java0/conc0301/DaemonThread.java b/03concurrency/0301/src/main/java/java0/conc0301/DaemonThread.java index acaea31e..192d5aac 100644 --- a/03concurrency/0301/src/main/java/java0/conc0301/DaemonThread.java +++ b/03concurrency/0301/src/main/java/java0/conc0301/DaemonThread.java @@ -4,16 +4,20 @@ public class DaemonThread { public static void main(String[] args) throws InterruptedException { Runnable task = () -> { - try { - Thread.sleep(5000); + try { + Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } - Thread t = Thread.currentThread(); - System.out.println("当前线程:" + t.getName()); + Thread t = Thread.currentThread(); + System.out.println("当前线程:" + t.getName()); }; Thread thread = new Thread(task); thread.setName("test-thread-1"); + + // 设置新线程为守护线程,当主线程退出时,若只剩下守护线程,JVM 会直接结束该进程 + // 因此新线程可能还没执行完就结束了,解决方法如下 + // 方法一:不设置新线程为守护线程,方法二:休眠主线程几秒,为新线程预留一点执行时间 thread.setDaemon(true); thread.start(); diff --git a/03concurrency/0301/src/main/java/java0/conc0301/op/Join.java b/03concurrency/0301/src/main/java/java0/conc0301/op/Join.java index 1cbf6a5a..cbe52e9a 100644 --- a/03concurrency/0301/src/main/java/java0/conc0301/op/Join.java +++ b/03concurrency/0301/src/main/java/java0/conc0301/op/Join.java @@ -3,14 +3,20 @@ public class Join { public static void main(String[] args) { + // 初始化 Object 类对象 oo,后面作为 synchronized 修饰的对象 Object oo = new Object(); - + + // 初始化一个新的线程对象 MyThread thread1 = new MyThread("thread1 -- "); //oo = thread1; + + // 将 oo 赋值到线程属性 Object 对象中,确保 run 方法中锁的对象和主线程是同一个 thread1.setOo(oo); thread1.start(); - - synchronized (oo) { // 这里用oo或thread1/this + + // 使用 oo 作为锁的对象,确保和新线程中 run 方法时同一个对象,使得两个线程需要争抢锁,保证线程安全 + // 还可以将 oo 改成 thread1,新线程 run 方法中改为 this,达到同样的目的 + synchronized (oo) { for (int i = 0; i < 100; i++) { if (i == 20) { try { diff --git a/03concurrency/0301/src/main/java/java0/conc0301/sync/TestSetGet.java b/03concurrency/0301/src/main/java/java0/conc0301/sync/TestSetGet.java index db251617..0d2e9151 100644 --- a/03concurrency/0301/src/main/java/java0/conc0301/sync/TestSetGet.java +++ b/03concurrency/0301/src/main/java/java0/conc0301/sync/TestSetGet.java @@ -5,18 +5,19 @@ public class TestSetGet { public static void main(String[] args) throws Exception { final SetGet s = new SetGet(); - Thread t = new Thread(){ - @Override - public void run() { - try { - s.get(); - } catch (Exception e) { - e.printStackTrace(); - } + Thread t = new Thread(() -> { + try { + s.get(); + } catch (Exception e) { + e.printStackTrace(); } - }; + }); t.start(); long start = System.currentTimeMillis(); + + // 主线程调用了 SetGet 类对象的 set 方法,该方法通过 synchronized 修饰 + // 又因为新线程调用的 SetGet 类对象 get 方法,也通过 synchronized 修饰 + // 并且主线程和新线程都作用于同一个对象 s,因此会与新线程争抢锁 s.set(10); System.out.println(" ... " + ( System.currentTimeMillis() - start )); @@ -26,16 +27,22 @@ public void run() { public static class SetGet { int a = 0; + + /** + * set 和 get 方法都使用了 synchronized 修饰 + * 当两个不同的线程,对同一个SetGet类对象,同一时间,分别调用了set和get,也需要争抢锁 + * 这个时候 synchronized 的锁对象就是 SetGet 类对象,等价于 synchronized (this) {} + */ public synchronized void set(int v) throws Exception { System.out.println(Thread.currentThread().getName() +" setting " +v); - Thread.sleep(1000); + Thread.sleep(5000); a = v; System.out.println(Thread.currentThread().getName() +" set " +v); } public synchronized int get() throws Exception { System.out.println(Thread.currentThread().getName() +" getting "); - Thread.sleep(10000); + Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " get "); return a; } diff --git a/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread2.java b/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread2.java index d0f0638b..ac876fd3 100644 --- a/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread2.java +++ b/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread2.java @@ -29,16 +29,8 @@ public synchronized void m4t2() { public static void main(String[] args) { final Thread2 myt2 = new Thread2(); - Thread t1 = new Thread(new Runnable() { - public void run() { - myt2.m4t1(); - } - }, "t1"); - Thread t2 = new Thread(new Runnable() { - public void run() { - myt2.m4t2(); - } - }, "t2"); + Thread t1 = new Thread(() -> myt2.m4t1(), "t1"); + Thread t2 = new Thread(() -> myt2.m4t2(), "t2"); t2.start(); t1.start(); } diff --git a/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread3.java b/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread3.java index f9d5d742..37d57be9 100644 --- a/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread3.java +++ b/03concurrency/0301/src/main/java/java0/conc0301/sync/Thread3.java @@ -27,28 +27,22 @@ private void m4t2() { } private void m4t1(Inner inner) { - synchronized (inner) { //使用对象锁 + // 使用对象锁 + synchronized (inner) { inner.m4t1(); } } private void m4t2(Inner inner) { + // m4t2 方法没有使用对象锁,因此可以让其他线程并行执行该方法 inner.m4t2(); } public static void main(String[] args) { final Thread3 myt3 = new Thread3(); final Inner inner = myt3.new Inner(); - Thread t1 = new Thread(new Runnable() { - public void run() { - myt3.m4t1(inner); - } - }, "t1"); - Thread t2 = new Thread(new Runnable() { - public void run() { - myt3.m4t2(inner); - } - }, "t2"); + Thread t1 = new Thread(() -> myt3.m4t1(inner), "t1"); + Thread t2 = new Thread(() -> myt3.m4t2(inner), "t2"); t1.start(); t2.start(); } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/atomic/AtomicMain.java b/03concurrency/0301/src/main/java/java0/conc0302/atomic/AtomicMain.java index 297eb343..8913b4cb 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/atomic/AtomicMain.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/atomic/AtomicMain.java @@ -5,13 +5,10 @@ public class AtomicMain { public static void main(String[] args) { final SyncCount count = new SyncCount(); - for (int i = 0; i < 100; i++) { - new Thread(new Runnable() { - @Override - public void run() { - for (int j = 0; j < 10000; j++) { - count.add(); - } + for (int i = 0; i < 10; i++) { + new Thread(() -> { + for (int j = 0; j < 10000; j++) { + count.add(); } }).start(); } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/atomic/LongDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/atomic/LongDemo.java index 6a7356c6..9c7e925f 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/atomic/LongDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/atomic/LongDemo.java @@ -10,14 +10,11 @@ public static void main(String[] args) { final AtomicLong atomicLong = new AtomicLong(); final LongAdder longAdder = new LongAdder(); - for (int i = 0; i < 100; i++) { - new Thread(new Runnable() { - @Override - public void run() { - for (int j = 0; j < 10000; j++) { - atomicLong.getAndIncrement(); - longAdder.increment(); - } + for (int i = 0; i < 10; i++) { + new Thread(() -> { + for (int j = 0; j < 10000; j++) { + atomicLong.getAndIncrement(); + longAdder.increment(); } }).start(); } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/atomic/SyncCount.java b/03concurrency/0301/src/main/java/java0/conc0302/atomic/SyncCount.java index b95c7cff..94714168 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/atomic/SyncCount.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/atomic/SyncCount.java @@ -10,6 +10,9 @@ public class SyncCount { private Lock lock = new ReentrantLock(true); + /** + * 显示的使用 Lock 来加锁和解锁 + */ public int add() { try { lock.lock(); diff --git a/03concurrency/0301/src/main/java/java0/conc0302/lock/LockSupportDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/lock/LockSupportDemo.java index 18f598f1..d6a91c5d 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/lock/LockSupportDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/lock/LockSupportDemo.java @@ -15,11 +15,16 @@ public ChangeObjectThread(String name) { @Override public void run() { synchronized (u) { System.out.println("in " + getName()); + /* + 无限期挂起当前执行线程,最常见的唤醒方法有两种: + - 其它线程调用了 unpark 方法,参数为被挂起的线程 + - 其它线程中断了被挂起的线程 + */ LockSupport.park(); if (Thread.currentThread().isInterrupted()) { - System.out.println("被中断了"); + System.out.println(getName() + "被中断了"); } - System.out.println("继续执行"); + System.out.println(getName() + "继续执行"); } } } @@ -29,8 +34,11 @@ public static void main(String[] args) throws InterruptedException { Thread.sleep(1000L); t2.start(); Thread.sleep(3000L); + // 中断被挂起的线程 t1,让它继续执行后面的逻辑 t1.interrupt(); + // 主线程调用 unpark 方法,唤醒被挂起的线程 t2 LockSupport.unpark(t2); + // 主线程等待 t1,t2 线程执行完毕 t1.join(); t2.join(); } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/lock/ReentrantLockDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/lock/ReentrantLockDemo.java index d0ff5f98..0d79c42b 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/lock/ReentrantLockDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/lock/ReentrantLockDemo.java @@ -22,4 +22,16 @@ public void run() { }.start(); } } + + /* + Thread-0 get begin + Thread-0 get end + Thread-1 get begin + Thread-1 get end + Thread-2 put begin + Thread-2 put end + Thread-3 put begin + Thread-3 put end + 读互斥、写互斥,都需要争抢锁 + */ } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/lock/TestFair.java b/03concurrency/0301/src/main/java/java0/conc0302/lock/TestFair.java index 1dc47538..87a69c2b 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/lock/TestFair.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/lock/TestFair.java @@ -4,35 +4,44 @@ import java.util.concurrent.locks.ReentrantLock; public class TestFair { - public static volatile int race=0; - public static ReentrantLock lock = new ReentrantLock(true); // 改成false会好100倍 + public static volatile int race = 0; + /** + * 可重入锁 + 公平锁 + * 改成false会好100倍 + */ + public static ReentrantLock lock = new ReentrantLock(true); + private static final int THREADS_COUNT = 10; + public static void increase(){ lock.lock(); - race++; //变量自增操作 + // 变量自增操作 + race++; lock.unlock(); } - private static final int THREADS_COUNT=20; + public static void main(String[]args){ int count = Thread.activeCount(); long now = System.currentTimeMillis(); System.out.println(count); - AtomicReference sign =new AtomicReference<>(); - Thread[]threads=new Thread[THREADS_COUNT]; //定义20个线程 - for(int i=0;i sign = new AtomicReference<>(); + // 定义10个线程 + Thread[]threads = new Thread[THREADS_COUNT]; + + for(int i = 0; i < THREADS_COUNT; i++){ + threads[i] = new Thread(() -> { + for(int i1 = 0; i1 < 100000; i1++){ + increase(); } }); threads[i].start(); - }//等待所有累加线程都结束 - while(Thread.activeCount()>count) { + } + //等待所有累加线程都结束 + while(Thread.activeCount() > count) { Thread.yield(); } - System.out.println(lock.getClass().getName() + " ts = "+ (System.currentTimeMillis()-now)); + System.out.println("race = " + race); + System.out.println(lock.getClass().getName() + " ts = "+ (System.currentTimeMillis() - now)); } } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExceptionDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExceptionDemo.java index 22240c51..1f5f51a5 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExceptionDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExceptionDemo.java @@ -7,9 +7,11 @@ public class ExceptionDemo { public static void main(String[] args) { + // 构建线程执行器,采用构造固定线程池的静态方法 ExecutorService executorService = Executors.newFixedThreadPool(1); try { + // 接收线程池执行结果(调用submit方法在主线程中,也能捕获线程池中抛出的异常) Future future = executorService.submit(() -> { throw new RuntimeException("executorService.submit()"); }); @@ -21,16 +23,17 @@ public static void main(String[] args) { System.out.println("catch submit"); ex.printStackTrace(); } -// -// try { -// executorService.execute(() -> { -// throw new RuntimeException("executorService.execute()"); -// }); -// } catch (Exception ex) { -// System.out.println("catch execute"); -// ex.printStackTrace(); -// } -// + + try { + // 调用execute方法,在主线程中捕获不到线程池中抛出的异常 + executorService.execute(() -> { + throw new RuntimeException("executorService.execute()"); + }); + } catch (Exception ex) { + System.out.println("catch execute"); + ex.printStackTrace(); + } + executorService.shutdown(); System.out.println("Main Thread End!"); } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExecutorServiceDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExecutorServiceDemo.java index 664b6942..9632f75f 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExecutorServiceDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/ExecutorServiceDemo.java @@ -8,6 +8,7 @@ public class ExecutorServiceDemo { public static void main(String[] args) { + // 创建一个线程池,可以安排命令在指定延迟时间 / 定期执行 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(16); try { String str = executorService.submit(new Callable() { @@ -21,6 +22,9 @@ public String call() throws Exception { } catch (Exception e) { e.printStackTrace(); } + + executorService.shutdown(); + System.out.println("Main Thread End!"); } } diff --git a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewCachedThreadPoolDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewCachedThreadPoolDemo.java index 2137af53..600d30fb 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewCachedThreadPoolDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewCachedThreadPoolDemo.java @@ -7,21 +7,23 @@ public class NewCachedThreadPoolDemo { public static void main(String[] args) { - + /* + 创建一个可缓存的线程池 + 如果线程池的大小超过了处理任务所需要的线程 + 那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务 + 此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小 + */ ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10000; i++) { final int no = i; - Runnable runnable = new Runnable() { - @Override - public void run() { - try { - System.out.println("start:" + no); - Thread.sleep(1000L); - System.out.println("end:" + no); - } catch (InterruptedException e) { - e.printStackTrace(); - } + Runnable runnable = () -> { + try { + System.out.println("start:" + no); + Thread.sleep(1000L); + System.out.println("end:" + no); + } catch (InterruptedException e) { + e.printStackTrace(); } }; executorService.execute(runnable); diff --git a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewFixedThreadPoolDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewFixedThreadPoolDemo.java index 8d4052b2..c997e93e 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewFixedThreadPoolDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewFixedThreadPoolDemo.java @@ -7,6 +7,7 @@ public class NewFixedThreadPoolDemo { public static void main(String[] args) { + // 构造一个固定大小为16的线程池 ExecutorService executorService = Executors.newFixedThreadPool(16); for (int i = 0; i < 100; i++) { final int no = i; diff --git a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewScheduledThreadExecutorDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewScheduledThreadExecutorDemo.java index 3a618f0c..d9744cc3 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewScheduledThreadExecutorDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewScheduledThreadExecutorDemo.java @@ -8,7 +8,7 @@ public class NewScheduledThreadExecutorDemo { public static void main(String[] args) { - + // 创建一个线程池,可以安排命令在指定延迟时间 / 定期执行 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(16); for (int i = 0; i < 100; i++) { diff --git a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewSingleThreadExecutorDemo.java b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewSingleThreadExecutorDemo.java index dee7b07c..f00f6a4f 100644 --- a/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewSingleThreadExecutorDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0302/threadpool/NewSingleThreadExecutorDemo.java @@ -8,6 +8,7 @@ public class NewSingleThreadExecutorDemo { public static void main(String[] args) { + // 创建单线程的线程池 ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { diff --git a/03concurrency/0301/src/main/java/java0/conc0303/collection/ConcurrentHashMapDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/collection/ConcurrentHashMapDemo.java index 1ec7f12b..6fea401a 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/collection/ConcurrentHashMapDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/collection/ConcurrentHashMapDemo.java @@ -14,28 +14,35 @@ public static void main(String[] args) { public static void demo1() { final Map count = new ConcurrentHashMap<>(); final CountDownLatch endLatch = new CountDownLatch(2); - Runnable task = new Runnable() { - @Override - public void run() { - AtomicInteger oldValue; - for (int i = 0; i < 5; i++) { - oldValue = count.get("a"); + Runnable task = () -> { + // 定义一个原子整型类变量 + AtomicInteger oldValue; + + // 循环5次,递增 oldValue 的整型数值属性 + for (int i = 0; i < 5; i++) { + // 获取在 ConcurrentHashMap 中的 key 为 a 的数值,赋值给 oldValue + oldValue = count.get("a"); + + // 第一次获取时,若没有这个值,则初始化该值为 0 + if (null == oldValue) { + AtomicInteger zeroValue = new AtomicInteger(0); + oldValue = count.putIfAbsent("a", zeroValue); if (null == oldValue) { - AtomicInteger zeroValue = new AtomicInteger(0); - oldValue = count.putIfAbsent("a", zeroValue); - if (null == oldValue) { - oldValue = zeroValue; - } + oldValue = zeroValue; } - oldValue.incrementAndGet(); } - endLatch.countDown(); + + oldValue.incrementAndGet(); } + + // 线程执行完毕后,调用 endLatch 对象的 countDown 方法,将等待数减 1,表示执行完毕 + endLatch.countDown(); }; new Thread(task).start(); new Thread(task).start(); try { + // 设置主线程等待两个线程执行完毕(通过等待数减为0判断) endLatch.await(); System.out.println(count); } catch (Exception e) { diff --git a/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo.java index df60dc64..76904231 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo.java @@ -22,7 +22,9 @@ public static void main(String[] args) { for (int i = 0; i < 10000; i++) { list.add(i); } - + + // 构建两个新的线程,一读一写,查看结果 + // 如果线程不安全会报错:java.util.ConcurrentModificationException T1 t1 = new T1(list); T2 t2 = new T2(list); t1.start(); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo1.java b/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo1.java index 82718cdb..1d76871d 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo1.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo1.java @@ -23,8 +23,13 @@ private void initData() { } private void start() { + // 初始化 mList 对象,为其构造数据 initData(); + // 构建固定大小值为10的线程池 ExecutorService service = Executors.newFixedThreadPool(THREAD_POOL_MAX_NUM); + + // 循环十次,将一读,一写的任务交给线程池来执行 + // 和CopyOnWriteArrayListDemo一样,如果集合不能保证读和写的线程安全,将会报错:java.util.ConcurrentModificationException for (int i = 0; i < THREAD_POOL_MAX_NUM; i++) { service.execute(new ListReader(this.mList)); service.execute(new ListWriter(this.mList, i)); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo2.java b/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo2.java index 94ae2427..aa3aa630 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo2.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/collection/CopyOnWriteArrayListDemo2.java @@ -14,36 +14,30 @@ public static void main(String[] args) { test(); } public static void test(){ - for(int i = 0; i<10000; i++){ + for(int i = 0; i < 10000; i++){ list.add("string" + i); } - new Thread(new Runnable() { - @Override - public void run() { - while (true) { - if (list.size() > 0) { // todo : 下一个get操作执行时,size可能已经是0了 - String content = list.get(list.size() - 1); - }else { - break; - } + new Thread(() -> { + while (true) { + if (list.size() > 0) { // todo : 下一个get操作执行时,size可能已经是0了 + String content = list.get(list.size() - 1); + }else { + break; } } }).start(); - new Thread(new Runnable() { - @Override - public void run() { - while (true) { - if(list.size() <= 0){ - break; - } - list.remove(0); - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } + new Thread(() -> { + while (true) { + if(list.size() <= 0){ + break; + } + list.remove(0); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); } } }).start(); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/collection/SyncListDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/collection/SyncListDemo.java index 95e2be28..97d03c8a 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/collection/SyncListDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/collection/SyncListDemo.java @@ -21,14 +21,12 @@ public static void main(String[] args) { // to do something System.out.println(Arrays.toString(list1.toArray())); - + + // 将集合对象 list1 中的顺序打乱 Collections.shuffle(list1); - - - + System.out.println(Arrays.toString(list1.toArray())); - - + // 假如不再修改 List list2 = Collections.unmodifiableList(list1); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/collection/TreeMapDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/collection/TreeMapDemo.java index bb04f20e..6906a43b 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/collection/TreeMapDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/collection/TreeMapDemo.java @@ -7,7 +7,7 @@ public class TreeMapDemo { public static void main(String[] args) { - // + // 构造TreeMap类对象,并制定其排序顺序按照逆序排序 TreeMap map = new TreeMap<>(Comparator.reverseOrder()); map.put(3, "val"); map.put(2, "val"); @@ -16,7 +16,8 @@ public static void main(String[] args) { map.put(4, "val"); // {5=val, 4=val, 3=val, 2=val, 1=val} System.out.println(map); - + + // 构造TreeMap类对象,并制定其排序顺序按照顺序排序 TreeMap map1 = new TreeMap<>(Comparator.naturalOrder()); map1.putAll(map); System.out.println(map1); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/future/CompletableFutureDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/future/CompletableFutureDemo.java index c5d1e900..7716e715 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/future/CompletableFutureDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/future/CompletableFutureDemo.java @@ -8,71 +8,91 @@ public static void main(String[] args){ // 1.变换结果 System.out.println("=====>1.变换结果"); - String result1 = CompletableFuture.supplyAsync(()->{return "Hello ";}).thenApplyAsync(v -> v + "world").join(); + String result1 = CompletableFuture + .supplyAsync(()-> "Hello ") + .thenApplyAsync(v -> v + "world") + .join(); System.out.println(result1); // 2.消费 - CompletableFuture.supplyAsync(()->{return "Hello ";}).thenAccept(v -> { System.out.println("=====>2.消费");System.out.println("consumer: " + v);}); + CompletableFuture + .supplyAsync(()-> "Hello ") + .thenAccept(v -> { + System.out.println("=====>2.消费"); + System.out.println("consumer: " + v); + }); // 3.组合 System.out.println("=====>3.组合"); - String result3 = CompletableFuture.supplyAsync(()->{ - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello"; - }).thenCombine(CompletableFuture.supplyAsync(()->{ - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "world"; - }),(s1,s2)->{return s1 + " " + s2;}).join(); + String result3 = CompletableFuture + .supplyAsync(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hello"; + }).thenCombine( + CompletableFuture.supplyAsync(()->{ + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "world"; + }), + (s1, s2)-> s1 + " " + s2 + ).join(); System.out.println("thenCombine:"+result3); - CompletableFuture.supplyAsync(() -> "Hello, java course.") - .thenApply(String::toUpperCase).thenCompose(s -> CompletableFuture.supplyAsync(s::toLowerCase)) - .thenAccept(v -> { System.out.println("thenCompose:"+v);}); + CompletableFuture + .supplyAsync(() -> "Hello, java course.") + .thenApply(String::toUpperCase) + .thenCompose(s -> CompletableFuture.supplyAsync(s::toLowerCase)) + .thenAccept(v -> System.out.println("thenCompose:" + v)); // 4.竞争 - System.out.println("=====>4.竞争"); - String result4 = CompletableFuture.supplyAsync(()->{ - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hi Boy"; - }).applyToEither(CompletableFuture.supplyAsync(()->{ - try { - Thread.sleep(300); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hi Girl"; - }),(s)->{return s;}).join(); + System.out.println("=====>4.竞争(两者先到先得)"); + String result4 = CompletableFuture + .supplyAsync(()->{ + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hi Boy"; + }).applyToEither( + CompletableFuture.supplyAsync(()->{ + try { + // 可改变休眠时间查看结果 + Thread.sleep(98); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hi Girl"; + }), + (s)-> s + ).join(); System.out.println(result4); // 5.补偿异常 System.out.println("=====>5.补偿异常"); - String result5 = CompletableFuture.supplyAsync(()->{ - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - if(true) { - throw new RuntimeException("exception test!"); - } + String result5 = CompletableFuture + .supplyAsync(()->{ + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if(true) { + throw new RuntimeException("exception test!"); + } - return "Hi Boy"; - }).exceptionally(e->{ // Fluent API - System.out.println(e.getMessage()); - return "Hello world!"; - }).join(); + return "Hi Boy"; + }).exceptionally(e -> { // Fluent API + System.out.println(e.getMessage()); + return "Hello world!"; + }).join(); System.out.println(result5); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/future/FutureDemo1.java b/03concurrency/0301/src/main/java/java0/conc0303/future/FutureDemo1.java index 14a16383..1886ab08 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/future/FutureDemo1.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/future/FutureDemo1.java @@ -6,11 +6,7 @@ public class FutureDemo1 { public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); - Future result = executor.submit(new Callable() { - public Integer call() throws Exception { - return new Random().nextInt(); - } - }); + Future result = executor.submit(() -> new Random().nextInt()); executor.shutdown(); try { System.out.println("result:" + result.get()); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/future/FutureTask1.java b/03concurrency/0301/src/main/java/java0/conc0303/future/FutureTask1.java index 69499819..4c8df69f 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/future/FutureTask1.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/future/FutureTask1.java @@ -6,14 +6,9 @@ public class FutureTask1 { public static void main(String[] args) { //第一种方式 - FutureTask task = new FutureTask(new Callable() { - @Override - public Integer call() throws Exception { - return new Random().nextInt(); - } - }); + FutureTask task = new FutureTask(() -> new Random().nextInt()); new Thread(task).start(); - //第二种方方式 + //第二种方方式(创建线程池来执行这个Runnable接口的实例) // ExecutorService executor = Executors.newSingleThreadExecutor(); // FutureTask task = new FutureTask(new Callable() { // @Override diff --git a/03concurrency/0301/src/main/java/java0/conc0303/stream/StreamParallelDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/stream/StreamParallelDemo.java index aaf9567d..df104331 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/stream/StreamParallelDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/stream/StreamParallelDemo.java @@ -9,18 +9,19 @@ public class StreamParallelDemo { public static void main(String[] args) { - List list = new ArrayList<>(); + List list = new ArrayList<>(10000); IntStream.range(1, 10000).forEach(i -> list.add(i)); BlockingQueue blockingQueue = new LinkedBlockingQueue(10000); + // Stream 的操作,可以简单的在原本单线程处理的代码上,通过加一个 .parallel + // 就把这个操作变成一个并行多线程的线程池来处理的这样的一个过程 List longList = list.stream().parallel() .map(i -> i.longValue()) .sorted() .collect(Collectors.toList()); // // 串行,单线程 -// longList.stream().forEach( +// longList.stream().forEach(i -> { // 并行,默认使用CPU * 2个线程 - longList.stream().forEach( - i -> { + longList.stream().parallel().forEach(i -> { try { blockingQueue.put(i); } catch (InterruptedException e) { @@ -28,6 +29,11 @@ public static void main(String[] args) { } }); System.out.println("blockingQueue:" + blockingQueue.toString()); + + /* + 我自己执行的时候,发现加了 .parallel 耗时反而增多了,可能原因是构造线程池需要 + 耗费一定的时间导致的;因此,当处理的数量不多时,直接用单线程的方式处理也许会更好 + */ } diff --git a/03concurrency/0301/src/main/java/java0/conc0303/threadlocal/ThreadLocalDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/threadlocal/ThreadLocalDemo.java index bbfe35e0..4fd36377 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/threadlocal/ThreadLocalDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/threadlocal/ThreadLocalDemo.java @@ -20,7 +20,8 @@ public int getNextNum() { public static void main(String[] args) { ThreadLocalDemo threadLocalMain = new ThreadLocalDemo(); - + + // 使用本地线程的实例对象,新建三个线程后,ThreadLocal 对象属性在各自线程中互不影响 SnThread client1 = new SnThread(threadLocalMain); SnThread client2 = new SnThread(threadLocalMain); SnThread client3 = new SnThread(threadLocalMain); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo.java index b93731be..c1324be5 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo.java @@ -5,27 +5,27 @@ public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(5); - for(int i=0;i<5;i++){ - new Thread(new readNum(i,countDownLatch)).start(); + for(int i = 0; i < 5; i++){ + new Thread(new readNum(i, countDownLatch)).start(); } countDownLatch.await(); // 注意跟CyclicBarrier不同,这里在主线程await System.out.println("==>各个子线程执行结束。。。。"); System.out.println("==>主线程执行结束。。。。"); } - static class readNum implements Runnable{ + static class readNum implements Runnable { private int id; private CountDownLatch latch; - public readNum(int id,CountDownLatch latch){ + public readNum(int id, CountDownLatch latch){ this.id = id; this.latch = latch; } @Override public void run() { synchronized (this){ - System.out.println("id:"+id+","+Thread.currentThread().getName()); + System.out.println("id:" + id + "," + Thread.currentThread().getName()); //latch.countDown(); - System.out.println("线程组任务"+id+"结束,其他任务继续"); + System.out.println("线程组任务" + id + "结束,其他任务继续"); latch.countDown(); } } diff --git a/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo2.java b/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo2.java index 62a1007a..0deaf16f 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo2.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/tool/CountDownLatchDemo2.java @@ -10,7 +10,7 @@ public class CountDownLatchDemo2 { private final static int threadCount = 200; public static void main(String[] args) throws Exception { - + ExecutorService exec = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadCount); @@ -30,7 +30,7 @@ public static void main(String[] args) throws Exception { } countDownLatch.await(); System.out.println("==>所有程序员完成任务,项目顺利上线!"); - //exec.shutdown(); + exec.shutdown(); } private static void test(int threadNum) throws Exception { diff --git a/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo.java b/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo.java index 628d980d..5f9d229e 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo.java @@ -13,7 +13,7 @@ public void run() { } }); for (int i = 0; i < 5; i++) { - new Thread(new readNum(i,cyclicBarrier)).start(); + new Thread(new readNum(i, cyclicBarrier)).start(); } // ==>>> @@ -27,17 +27,17 @@ public void run() { // new Thread(new readNum(i,cyclicBarrier)).start(); // } } - static class readNum implements Runnable{ + static class readNum implements Runnable { private int id; private CyclicBarrier cyc; - public readNum(int id,CyclicBarrier cyc){ + public readNum(int id, CyclicBarrier cyc){ this.id = id; this.cyc = cyc; } @Override public void run() { synchronized (this){ - System.out.println("id:"+id+","+Thread.currentThread().getName()); + System.out.println("id:" + id + "," + Thread.currentThread().getName()); try { cyc.await(); System.out.println("线程组任务" + id + "结束,其他任务继续"); diff --git a/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo2.java b/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo2.java index 33e88260..b988023f 100644 --- a/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo2.java +++ b/03concurrency/0301/src/main/java/java0/conc0303/tool/CyclicBarrierDemo2.java @@ -8,7 +8,7 @@ public static void main(String[] args) { int N = 4; CyclicBarrier barrier = new CyclicBarrier(N); - for(int i=0;i CyclicBarrier重用"); - for(int i=0;i { try { - semaphore.acquire(3); // 获取全部许可,退化成串行执行 + // 获取全部许可,退化成串行执行 + // 相当于阻止3个线程运行,除去主线程外,就允许线程池中一个线程运行 + // 可将这个值改为2,查看一下结果 + semaphore.acquire(3); test(threadNum); - semaphore.release(3); // 释放多个许可 + // 释放多个许可 + semaphore.release(3); } catch (Exception e) { e.printStackTrace(); } diff --git a/04fx/spring01/src/main/java/io/kimmking/spring02/Aop1.java b/04fx/spring01/src/main/java/io/kimmking/spring02/Aop1.java index fa919d39..cb0c90ef 100644 --- a/04fx/spring01/src/main/java/io/kimmking/spring02/Aop1.java +++ b/04fx/spring01/src/main/java/io/kimmking/spring02/Aop1.java @@ -3,24 +3,38 @@ import org.aspectj.lang.ProceedingJoinPoint; public class Aop1 { + /* + Spring 做 AOP 第一种方式:用代码和XML配置的方式来配置 + - 在类中写了三个方法,名叫 startTransaction, commitTransaction, around + - 特别注意:around 的参数必须是 ProceedingJoinPoint + - 在 Spring 配置文件中,将做 AOP 的类 Aop1 注册成一个 Bean + - 参考 resources/applicationContext.xml 第40行 + - 然后我们就可以定义我们的 AOP + - 参考 resources/applicationContext.xml 第47行 + - 先定义一个切点 + - 再定义一个切面 + - 然后把两个匹配到一块儿,就可以让切面的代码作用到所有切点上去 + - Tips:这里我们定义的切点是一个表达式,这个表达式可以用来匹配我们的包路径,类名,方法名,包括参数 + - 详情可以去看网上文章或者相关书籍 + */ - //前置通知 - public void startTransaction(){ - System.out.println(" ====>begin ding... "); //2 - } + //前置通知 + public void startTransaction(){ + System.out.println(" ====>begin ding... "); //2 + } - //后置通知 - public void commitTransaction(){ - System.out.println(" ====>finish ding... "); //4 - } + //后置通知 + public void commitTransaction(){ + System.out.println(" ====>finish ding... "); //4 + } - //环绕通知 - public void around(ProceedingJoinPoint joinPoint) throws Throwable{ - System.out.println(" ====>around begin ding"); //1 - //调用process()方法才会真正的执行实际被代理的方法 - joinPoint.proceed(); - - System.out.println(" ====>around finish ding"); //3 - } + //环绕通知 + public void around(ProceedingJoinPoint joinPoint) throws Throwable{ + System.out.println(" ====>around begin ding"); //1 + //调用process()方法才会真正的执行实际被代理的方法 + joinPoint.proceed(); + + System.out.println(" ====>around finish ding"); //3 + } } diff --git a/04fx/spring01/src/main/java/io/kimmking/spring02/Aop2.java b/04fx/spring01/src/main/java/io/kimmking/spring02/Aop2.java index 4edbe006..3da66624 100644 --- a/04fx/spring01/src/main/java/io/kimmking/spring02/Aop2.java +++ b/04fx/spring01/src/main/java/io/kimmking/spring02/Aop2.java @@ -10,6 +10,19 @@ @Aspect public class Aop2 { + /* + Spring 做 AOP 第二种方式:用全注解方式来配置(与第一种方式是等价的) + - 定义了一个 AOP 切面的类 Aop2,开启了它上面的切面注解 @Aspect 表示整个类就是一个切面 + - 定义了一个方法 point (空的就可以了),在上面我们定义了一个切点(明确是 Klass 类相关的 dong 方法) + - 再定义三个方法 + - 用 @Before 注解修饰的 before 方法 + - 用 @AfterReturning 注解修饰的 after 方法 + - 用 @Around 注解修饰的 around 方法 + - 每个注解里面需要给定一个 point(),表示对应的切点 + + - 在配置文件中开启自动代理,它就会扫描到用注解配置的一些切面 + - 参考 resources/applicationContext.xml 第45行 + */ @Pointcut(value="execution(* io.kimmking.*.Klass.*dong(..))") public void point(){ diff --git a/04fx/spring01/src/main/java/io/kimmking/spring02/School.java b/04fx/spring01/src/main/java/io/kimmking/spring02/School.java index 7c700e64..4c287552 100644 --- a/04fx/spring01/src/main/java/io/kimmking/spring02/School.java +++ b/04fx/spring01/src/main/java/io/kimmking/spring02/School.java @@ -9,7 +9,16 @@ @Data public class School implements ISchool { - + /* + @Autowire 和 @Resource 是两种常用的注入方法 + @Autowire 是默认按照类型来注入的 + - 注入时可使用 required 参数,值为 ture 和 false,表示我们是在启动的时候就要 + 找到 Klass,把它先配置好;还是当我们调用 Klass 的某个属性方法的时候,再看它 + 要不要装配,再拿到装配(懒加载) + + @Resource 是默认按名字来注入的 + */ + // Resource @Autowired(required = true) //primary Klass class1; diff --git a/04fx/spring01/src/main/java/io/kimmking/spring02/SpringDemo01.java b/04fx/spring01/src/main/java/io/kimmking/spring02/SpringDemo01.java index a6263369..e87a009e 100644 --- a/04fx/spring01/src/main/java/io/kimmking/spring02/SpringDemo01.java +++ b/04fx/spring01/src/main/java/io/kimmking/spring02/SpringDemo01.java @@ -8,7 +8,8 @@ public class SpringDemo01 { public static void main(String[] args) { - + // 为了更加方便查看 Spring 的执行过程,将 Student 和 Klass 都在配置文件中注册了 Bean + ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // Student student123 = context.getBean(Student.class); diff --git a/04fx/spring01/src/main/resources/applicationContext.xml b/04fx/spring01/src/main/resources/applicationContext.xml index 681cf409..356a0469 100644 --- a/04fx/spring01/src/main/resources/applicationContext.xml +++ b/04fx/spring01/src/main/resources/applicationContext.xml @@ -40,7 +40,8 @@ - + +