JUC學習筆記(三)
阿新 • • 發佈:2021-08-09
JUC學習筆記(一)https://www.cnblogs.com/lm66/p/15118407.html
JUC學習筆記(二)https://www.cnblogs.com/lm66/p/15118813.html
1、執行緒間通訊
執行緒間通訊的模型有兩種:共享記憶體和訊息傳遞,以下方式都是基本這兩種模型來實現的。我們來基本一道面試常見的題目來分析
場景---兩個執行緒,一個執行緒對當前數值加 1,另一個執行緒對當前數值減 1,要求用執行緒間通訊
1.1、synchronized 方案
public class ThreadDemo1 { public static void main(String[] args) { Share share = new Share(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.increment(); } catch (Exception e) { e.printStackTrace(); } } }, "AA").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.decrement(); } catch (Exception e) { e.printStackTrace(); } } }, "BB").start(); } } class Share { private int num = 0; public synchronized void increment() throws Exception { while (num != 0) { this.wait(); } num++; System.out.println(Thread.currentThread().getName() + "::" + num); this.notifyAll(); } public synchronized void decrement() throws Exception { while (num != 1) { this.wait(); } num--; System.out.println(Thread.currentThread().getName() + "::" + num); this.notifyAll(); } }
1.2、Lock方案
public class ThreadDemo2 { public static void main(String[] args) { Share2 share = new Share2(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.increment(); } catch (Exception e) { e.printStackTrace(); } } }, "AA").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { share.decrement(); } catch (Exception e) { e.printStackTrace(); } } }, "BB").start(); } } class Share2 { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private int num = 0; public void increment() throws Exception { lock.lock(); try { while (num != 0) { condition.await(); } num++; System.out.println(Thread.currentThread().getName() + "::" + num); condition.signalAll(); } finally { lock.unlock(); } } public void decrement() throws Exception { lock.lock(); try { while (num != 1) { condition.await(); } num--; System.out.println(Thread.currentThread().getName() + "::" + num); condition.signalAll(); } finally { lock.unlock(); } } }
1.3、執行緒間定製化通訊
1.3.1、案例介紹
問題: A 執行緒列印 5 次 A,B 執行緒列印 10 次 B,C 執行緒列印 15 次 C,按照此順序迴圈 10 輪
1.3.2、實現流程
public class ThreadDemo3 { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { shareResource.print5(i); } catch (Exception e) { } } },"AA").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { shareResource.print10(i); } catch (Exception e) { } } },"BB").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { try { shareResource.print15(i); } catch (Exception e) { } } },"CC").start(); } } class ShareResource { // 定義標誌位 private int flag = 1; // 建立Lock鎖 private Lock lock = new ReentrantLock(); private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); public void print5(int loop) throws Exception { lock.lock(); try { // 判斷。防止虛假喚醒 while (flag != 1) { // 等待 c1.await(); } for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "::" + loop); } // 修改標誌位 flag = 2; // 通知 c2.signal(); } finally { lock.unlock(); } } public void print10(int loop) throws Exception { lock.lock(); try { while (flag != 2) { c2.await(); } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "::" + loop); } flag = 3; c3.signal(); } finally { lock.unlock(); } } public void print15(int loop) throws Exception { lock.lock(); try { while (flag != 3) { c3.await(); } for (int i = 0; i < 15; i++) { System.out.println(Thread.currentThread().getName() + "::" + loop); } flag = 1; c1.signal(); } finally { lock.unlock(); } } }