线程间通信的几种实现方式
题目:有多个个线程分别对int number操作,一共操作十次,当number等于0时number加一,当number等于1时number减一。
方式一:使用Object类的wait() 和 notifyAll() 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| class Share {
private int number = 0;
public synchronized void incr() throws InterruptedException { if (number != 0) { this.wait(); } number++; System.out.println(Thread.currentThread().getName() + " :: " + number); this.notifyAll(); }
public synchronized void decr() throws InterruptedException { if (number != 1) { this.wait(); } number--; System.out.println(Thread.currentThread().getName() + " :: " + number); this.notifyAll(); } }
public class ThreadDemo1 { public static void main(String[] args) { Share share = new Share(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "AA").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "BB").start(); } }
|
输出:

虚假唤醒问题
这里我们创建4个线程发别执行加减的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class ThreadDemo1 { public static void main(String[] args) { Share share = new Share(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "AA").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "BB").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "CC").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "DD").start(); } }
|
可以看到结果和预期不一致

解决方法:使用while判断,线程被唤醒时还要经过判断才往下走
1 2 3 4 5 6 7 8 9 10 11 12
| public synchronized void incr() throws InterruptedException { while (number != 0) { this.wait(); } number++; System.out.println(Thread.currentThread().getName() + " :: " + number); this.notifyAll(); }
|
方式二:使用 ReentrantLock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| class Share { private int number = 0;
private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition();
public void incr() throws InterruptedException { lock.lock(); try { while (number != 0) { condition.await(); } number++; System.out.println(Thread.currentThread().getName() + " :: " + number); condition.signalAll(); } finally { lock.unlock(); } }
public void decr() throws InterruptedException { lock.lock(); try { while (number != 1) { condition.await(); } number--; System.out.println(Thread.currentThread().getName() + " :: " + number); condition.signalAll(); } finally { lock.unlock(); } } }
public class ThreadDemo2 { public static void main(String[] args) { Share share = new Share(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "AA").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "BB").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.incr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "CC").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { share.decr(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "DD").start(); } }
|
运行结果为:

线程间定制化通信
synchronized实现线程间通信的案例如果有多个线程那么就无法指定线程执行的顺序,我们可以使用Lock锁的Condition 实现线程定制化通信
实例:
A线程打印2次A,B线程打印3次B,C线程打印5次C,按照此顺序循环10轮
思路:创建三个线程给每个线程设置一个标志位
线程A判断flag=0,打印2次,修改flag=1,通知线程B
线程B判断flag=1,打印3次,修改flag=2,通知线程C
线程C判断flag=2,打印5次,修改flag=0,通知线程A
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
class ShareResource {
private int flag = 1;
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 InterruptedException { lock.lock(); try { while (flag != 1) { c1.await(); } for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName() + " :: " + i + " :轮数" + loop); } flag = 2; c2.signal(); } finally { lock.unlock(); } }
public void print10(int loop) throws InterruptedException { lock.lock(); try { while (flag != 2) { c2.await(); } for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName() + " :: " + i + " :轮数" + loop); } flag = 3; c3.signal(); } finally { lock.unlock(); } }
public void print15(int loop) throws InterruptedException { lock.lock(); try { while (flag != 3) { c3.await(); } for (int i = 1; i <= 15; i++) { System.out.println(Thread.currentThread().getName() + " :: " + i + " :轮数" + loop); } flag = 1; c1.signal(); } finally { lock.unlock(); } } }
public class ThreadDemo3 { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { shareResource.print5(i); } catch (InterruptedException e) { e.printStackTrace(); } } }, "AA").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { shareResource.print10(i); } catch (InterruptedException e) { e.printStackTrace(); } } }, "BB").start(); new Thread(() -> { for (int i = 1; i <= 15; i++) { try { shareResource.print15(i); } catch (InterruptedException e) { e.printStackTrace(); } } }, "CC").start(); } }
|
输出结果为:
