当前位置: 代码迷 >> 综合 >> 线程之间的通信
  详细解决方案

线程之间的通信

热度:98   发布时间:2024-03-08 16:48:54.0

线程之间的通信在使用wait和notify进行通信时(所有对象都会有着两个方法),必须搭配synchronized使用,wait是会等待并释放锁,直到调用notify或notifyAll通知该锁对象,而调用notify方法不释放锁,下面讲述线程通信从初始版本到最终完整版的实现示例。

初始版

在不使用wait和notify时,普通的通信方式显得很傻,消耗无必要的资源,如下所示。

package com.lydon.thread;import java.util.*;/*** 不好的线程之间通信实现方式*/
public class ListAdd1 {private volatile static List<String> list=new ArrayList<>();public void add(){list.add("ddddd");}public  int size(){return list.size();}public static void main(String[] args) {final ListAdd1 listAdd1=new ListAdd1();Thread thread1=new Thread(()-> {try {for (int i = 0; i < 10; i++) {listAdd1.add();System.out.println("当前线程"+Thread.currentThread().getName()+"添加了一个元素");Thread.sleep(500);}} catch (InterruptedException e) {e.printStackTrace();}});Thread thread2=new Thread(()->{while (true){if(listAdd1.size()==5){System.out.println("当前线程"+Thread.currentThread().getName()+"收到了通知");throw new RuntimeException();}}});thread1.start();thread2.start();}
}

中级版,结合synchronized使用notifity和wait进行通信,优化版如下:

package com.lydon.thread;import java.util.*;/*** 线程之间通信方法示例,使用wait与notify,其中wait等待释放锁,有区别于sheep(不释放锁),而notify同样也不是释放锁*/
public class ListAdd2 {private volatile static List<String> list=new ArrayList<>();public void add(){list.add("ddddd");}public  int size(){return list.size();}public static void main(String[] args) {final ListAdd1 listAdd1=new ListAdd1();Thread thread1=new Thread(()-> {try {synchronized (listAdd1){for (int i = 0; i < 10; i++) {listAdd1.add();System.out.println("当前线程"+Thread.currentThread().getName()+"添加了一个元素");Thread.sleep(500);if(listAdd1.size()==5){System.out.println("当前线程"+Thread.currentThread().getName()+"发出了通知");listAdd1.notify();}}}} catch (InterruptedException e) {e.printStackTrace();}},"thread1");Thread thread2=new Thread(()->{synchronized (listAdd1) {if(listAdd1.size()!=5){try {listAdd1.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("当前线程"+Thread.currentThread().getName()+"收到了通知");throw new RuntimeException();}}},"thread2");thread2.start();thread1.start();}
}

输出结果为:

输出结果为:
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1发出了通知
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread2收到了通知
Exception in thread "thread2" java.lang.RuntimeExceptionat com.lydon.thread.ListAdd2.lambda$main$1(ListAdd2.java:48)at java.lang.Thread.run(Thread.java:745)Process finished with exit code 0

我们可以看到,中级版对比初级版来说,在需要通信时才通知的问题,thread2不用一直for循环等待,但要注意的是使用wait和notify时,都要锁定某个锁。但这种也有弊端,在thread1发出通知后,后续的操作并没有停止下来,而是继续执行,跟实际的使用场景不符,因此我们还需要个高级版来完善这个问题:

package com.lydon.thread;import java.util.*;
import java.util.concurrent.*;/*** 线程之间通信方法示例,使用wait与notify,其中wait等待释放锁,有区别于sheep(不释放锁),而notify同样也不是释放锁*/
public class ListAdd3 {private volatile static List<String> list=new ArrayList<>();public void add(){list.add("ddddd");}public  int size(){return list.size();}public static void main(String[] args) {final ListAdd1 listAdd1=new ListAdd1();CountDownLatch countDownLatch=new CountDownLatch(1);Thread thread1=new Thread(()-> {try {for (int i = 0; i < 10; i++) {listAdd1.add();System.out.println("当前线程"+Thread.currentThread().getName()+"添加了一个元素");Thread.sleep(500);if(listAdd1.size()==5){System.out.println("当前线程"+Thread.currentThread().getName()+"发出了通知");countDownLatch.countDown();}}} catch (InterruptedException e) {e.printStackTrace();}},"thread1");Thread thread2=new Thread(()->{synchronized (listAdd1) {if(listAdd1.size()!=5){try {countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("当前线程"+Thread.currentThread().getName()+"收到了通知");throw new RuntimeException();}}},"thread2");thread2.start();thread1.start();}
}

输出为:

当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1发出了通知
Exception in thread "thread2" java.lang.RuntimeException
当前线程thread1添加了一个元素at com.lydon.thread.ListAdd3.lambda$main$1(ListAdd3.java:48)
当前线程thread2收到了通知at java.lang.Thread.run(Thread.java:745)
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素
当前线程thread1添加了一个元素

使用了CountDownLatch计数器来操作,由于是针对线程的原子性操作,因此不用使用synchronized来修饰整段语句

  相关解决方案