1、wait()/notify()

Object类中相关的方法有notify和wait方法,又因为它俩被定义在Object类中,故会被所有的类继承。它俩都是final的,不能被重写,不能通过子类重写改变。

wait()方法

让当前线程进入等待,并释放锁
注意:(1)当前线程必须拥有当前对象的monitor,也就是lock锁。这样才能调用wait()方法,否则会抛出异常
(2)线程调用wait方法,释放它对锁的拥有权,然后等待另外的线程来通知它(notify或notifyAll方法),这样他才能重新获得锁的拥有权和恢复执行
(3)要确保调用wait方法时拥有锁,即必须在同步方法或同步代码块中被调用

wait(long)方法

让当前线程进入等待,并释放锁。等待时间为long,超过这个时间没有唤醒当前线程,就自动唤醒。

notify()方法

让当前线程通知那些正处于等待状态的线程,当前线程执行完毕后释放锁,并从其他线程中唤醒一个,继续执行
注意:(1)若多个线程在等待,只有一个会被选择唤醒,选择是随意的,跟具体实现有关
(2)线程被唤醒也不能执行,必须等到当前线程释放了这个对象的锁

notifyAll()方法

让当前线程通知那些正处于等待状态的线程,当前线程执行完毕后释放锁,唤醒所有等待状态的线程

wait()和sleep()区别

线程调用wait方法,就会释放掉对象的锁。
Thread.sleep会导致线程睡眠指定的毫秒数,睡觉的时候是不会释放锁的。

wait()和notify()协作的注意事项

a.通知过早
如果通知过早,就会打乱程序的执行逻辑。

public class MyRun {private String lock = new String("");public Runnable runnableA = new Runnable() {@Overridepublic void run() {try {synchronized (lock){System.out.println("开始wait");lock.wait();System.out.println("结束wait");}}catch (InterruptedException e){e.printStackTrace();}}};public Runnable runnableB = new Runnable() {@Overridepublic void run() {synchronized (lock){System.out.println("开始notify");lock.notify();System.out.println("结束notify");}}};public static void main(String []args) throws InterruptedException{MyRun run = new MyRun();Thread threadB = new Thread(run.runnableB);threadB.start();threadB.sleep(100);Thread threadA = new Thread(run.runnableA);threadA.start();}
}

notify()先执行,会使得wait()释放锁之后,进入等待状态,永远无法被唤醒。

开始notify
结束notify
开始wait

b.等待wait的条件发生变化
再使用wait/notify模式时,wait等待条件发生改变,也会导致程序逻辑混乱
Add类执行加法操作,然后通知Subtract类

public class Add {private String lock;public Add(String lock) {super();this.lock = lock;}public void add(){synchronized (lock){ValueObject.list.add("anyThings");lock.notifyAll();}}
}

Subtract执行减法操作,进入等待状态,等待Add类唤醒notify

public class Subtract {private String lock;public Subtract(String lock) {super();this.lock = lock;}public void subtract(){try {synchronized (lock){if (ValueObject.list.size()==0){System.out.println(Thread.currentThread().getName()+"线程开始");lock.wait();System.out.println(Thread.currentThread().getName()+"线程结束");}ValueObject.list.remove(0);System.out.println("list长度:"+ValueObject.list.size);}}catch (InterruptedException e){e.printStackTrace();}}
}

线程ThreadAdd

public class ThreadAdd extends Thread {private Add pAdd;public ThreadAdd(Add pAdd) {super();this.pAdd = pAdd;}@Overridepublic void run() {pAdd.add();}
}

线程ThreadSubtract

public class ThreadSubtract extends Thread {private Subtract mSubtract;public ThreadSubtract(Subtract subtract) {super();mSubtract = subtract;}@Overridepublic void run() {mSubtract.subtract();}
}

先开启2个ThreadSubtract,list为空,进入等待状态。在开启1个ThreadAdd线程,向list中添加一个元素,然后唤醒2个ThreadSubtract

public class AddTest {public static void main(String []args) throws InterruptedException{String lock = new String("");Add add = new Add(lock);Subtract subtract = new Subtract(lock);ThreadSubtract subtract1 = new ThreadSubtract(subtract);subtract1.setName("subtract1");subtract1.start();ThreadSubtract subtract2 = new ThreadSubtract(subtract);subtract2.setName("subtract2");subtract2.start();Thread.sleep(1000);ThreadAdd threadAdd = new ThreadAdd(add);threadAdd.setName("threadAdd");threadAdd.start();}
}

第2个ThreadSubtract执行减法操作时,提示下标越界。因为一开始启动了2个ThreadSubtract,等待。ThreadAdd添加1个元素唤醒所有线程,第1个ThreadSubtract接着之前的操作继续执行,删除一个元素并输出集合大小。第2个ThreadSubtract也执行到这的时候,元素已经没有了,就抛异常。
**解决:**从等待状态被唤醒后,重新判断条件,判断是否仍然需要进入等待状态。不需要,才进行下一步。也就是if换成while

public void subtract(){try {synchronized (lock){while (ValueObject.list.size()==0){System.out.println(Thread.currentThread().getName()+"线程开始");lock.wait();System.out.println(Thread.currentThread().getName()+"线程结束");}ValueObject.list.remove(0);System.out.println("list长度:"+ValueObject.list.size);}}catch (InterruptedException e){e.printStackTrace();}}

2、Condition实现等待/通知

关键字synchronized和wait、notify、notifyAll结合,可以实现等待/通知模式。当然ReentrantLock借助Condition对象也可以实现。
condition.await()——>lock.wait()
condition.await(Long time,TimeUnit unit)——>lock.wait(long timeout)
condition.signal()——>lock.notify()
condition.signalAll()——>lock.notifyAll()
synchronized相当于整个ReentrantLock对象只有一个单一的Condition对象,而ReentrantLock却可以有多个Condition对象来通知部分线程。ConditionA.await()进入等待,就有ConditionA.signalAll()通知唤醒。ConditionB.await()进入等待,就有ConditionB.signalAll()通知唤醒。

线程间通信的两种方式相关推荐

  1. 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  2. 线程间协作的两种方式:wait、notify、notifyAll和Condition

    转载自  线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当 ...

  3. JAVA线程间通信的几种方式

    今天在群里面看到一个很有意思的面试题: "编写两个线程,一个线程打印1~25,另一个线程打印字母A~Z,打印顺序为12A34B56C--5152Z,要求使用线程间的通信." 这是一 ...

  4. python 线程通信的几种方式_进程间通信和线程间通信的几种方式

    进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在当代 ...

  5. 线程间通信的几种方式

    Java线程间通信: 1:线程上下文 2:共享内存 3:IPC通信 4:套接字(Socket),不同的机器之间进行通信 另外:附注通信内容: linux常用的进程间的通讯方式 (1).管道(pipe) ...

  6. 进程间通信和线程间通信的几种方式

    进程和线程的区别: 对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品. 而线程,相对于进程而言,是一个更加接近于执行体的概念,可以和同进程的其他线程之间直接共享数 ...

  7. java实现线程间通信的四种方式

    synchronized同步 public class MyObject { synchronized public void methodA() { //do something.... } syn ...

  8. java 线程间通信的几种方式

    1.如何让两个线程依次执行 假设有两个线程,一个线程A,一个线程B,两个线程分别依次打印 1-3 三个数字即可. package Test;/** /*** @author Administrator ...

  9. 线程间通信的几种实现方式

    线程间通信的几种实现方式 首先,要短信线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的.我们来基本一道面试常见的题目来分析: 题目:有两个线程A.B,A线程向一个集合里面 ...

最新文章

  1. 一篇为你讲透Yii2的widget这货
  2. Android开发之如何保证Service不被杀掉(broadcast+system/app)
  3. centos7 开启 关闭 NetworkManager
  4. Hibernate面试题
  5. url中携带中文乱码问题
  6. 函数⑥作用域与命名空间
  7. CF198D Cube Snake(三维空间/增量构造)
  8. Bootstrap学习笔记01
  9. mysql导入greenplum_greenPlum中通过gpfdist导入文本数据到数据库表中
  10. html之关于空白和空白字符
  11. Josephus问题的Java解决方法
  12. 黑马程序员pink老师前端入门教程,零基础必看的JavaScript基础语法视频教程(jQuery2)
  13. 黑马程序员并发编程笔记(一)
  14. error LNK2019: 无法解析的外部符号 _WinMain@16,该符号在函数 ___tmainCR...
  15. 身份证姓名手机号银行卡号邮箱 “ * “ 号隐藏
  16. 喜欢我们不如加入我们:来投稿吧,稿酬靠谱!
  17. 使用python+selenium清空淘宝购物车
  18. 买天文望远镜必看——已知望远镜焦距、相机画幅,求视场(附代码,实时更新)
  19. excel 使用技巧小总结
  20. SAP CRM BOL entity deletion - root node and sub node

热门文章

  1. class.forname找不到类_15个“专科专业”就业找工作容易,关注热度也挺高,报考比较靠谱...
  2. python有关迭代器和生成器的面试题_【面试题 | Python中迭代器和生成器的区别?】- 环球网校...
  3. Micropython教程之TPYBoard开发板DIY智能温控小风扇(萝卜学科编程教育)
  4. Windows Server 2008自定义任务栏和开始菜单
  5. ajax查找错误信息
  6. Atitit.eclipse 4.3 4.4  4.5 4.6新特性
  7. 【转】java提高篇(十)-----详解匿名内部类
  8. 开源项目PullToRefresh详解(一)——PullToRefreshListView
  9. php的数组与字符串的转换函数整理
  10. 无法使用index seek的写法