我们先看看代码片段,有点类似生产者-消费者模型中的生产者的逻辑代码。
public synchronized void push(Object obj){
while( condition ){
try{
this.wait(); //等待,直到有数据出栈
}catch(InterruptedException e){
}
}
//do something
stack.push(obj);
this.notify(); //通知其它线程把数据出栈
}
注意第4行,代码执行到这里会发生什么状态?
push方法的签名中有synchronized修饰,所以此方法具有排他性,锁(资源)为自身实例对象,也就是说同时同一个对象的这个方法只能被一个线程所执行,那么当执行到第4行时会发生什么呢? XX一紧,线程在释放排他锁资源之前,自己把自己给阻塞了? 这样岂不是死锁了?
翻翻JDK1.6手册,便恍然大悟:
wait方法共有3个重载函数:
- public final void wait(long timeout)
throws InterruptedException
- public final void wait(long timeout, int nanos) throws InterruptedException
- public final void wait() throws InterruptedException
在其他线程调用此对象的
notify()
方法或
notifyAll()
方法,或者超过指定的时间量前,导致当前线程等待。此方法导致当前线程(称之为
T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度目的,在发生以下四种情况之一前,线程
T 被禁用,且处于休眠状态:
- 其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。
- 其他某个线程调用此对象的 notifyAll 方法。
- 其他某个线程中断线程
T。
- 大约已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。
然后,从对象的等待集中删除线程
T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用
wait 方法时的情况。然后,线程 T 从 wait 方法的调用中返回。所以,从
wait 方法返回时,该对象和线程 T 的同步状态与调用 wait 方法时的情况完全相同。
简而言之:
- wait方法的作用释放已持有的锁,并进入休眠状态;当被唤醒或是等待超时,当前的线程又会重新加入到锁等待队列中,一旦获取了对该对象的控制权,则会从原来的地方继续执行;如果线程被中断,则会抛出InterruptedException异常。
- notify方法唤醒等待队列中的第一个线程并把它移入锁申请队列中
- notifyAll方法唤醒等待队列中的所有的线程并把它们移入锁申请队列中
- wait,notify,notifyAll必须在已经持有锁的情况下执行,所以它们只能出现在synchronized作用范围内,也就是出现在用synchronized修饰的方法或代码块中.
- 在更多线程的情况下(e.g. 拿消费者/生产者模型来讲,可能存在多个消费者和多个生产者),线程被唤醒后依然需要对条件进行测试,如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中。如上述代码示例(2-7循环体)
附上完整的示例代码:
public class ThreadDemo {
private int x = 0;
public synchronized void add() {
while (x >= 2) {
try {
this.wait();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
x++;
System.out.println("add:" + x);
this.notifyAll();
}
public synchronized void sub() {
int y = 1;
while (x < 2) {
System.out.println("sub:while repeat = " + y);
y++;
try {
this.wait(); //this.wait(1);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
x--;
System.out.println("sub:" + x);
this.notifyAll();
}
public static void main(String[] args) throws Throwable {
final ThreadDemo tt = new ThreadDemo();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; i++) {
tt.add();
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; i++) {
tt.sub();
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
}
}
}
}).start();
}
}
在代码第25行处,可以试着设置下等待超时时间,然后看看测试结果。
分享到:
相关推荐
源码—Java多线程5—死锁和wait notify notifyAll
Java 同步方式 wait和notify/notifyall
主要介绍了Java多线程中wait、notify、notifyAll使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。 在 Java 中可以用 wait、notify 和 notifyAll 来实现...
主线程去控制子线程wait与notify
开一个子线程来完成一个循环处理的工作,我在主线程中能灵活控制这个子线程的开始、暂停/继续、结束。
主要介绍了Java 中Object的wait() notify() notifyAll()方法使用的相关资料,需要的朋友可以参考下
使用Java多线程的wait和notify方法实现最简单的生产者消费者模式
主要介绍了java多线程wait,notify,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面小编和大家一起来学习一下吧
本篇文章对Java中多线程notify与notifyall的区别进行了详细的分析介绍。需要的朋友参考下
Java多线程同步(wait()notify()notifyAll())[文].pdf
文章目录1 wait、notify、notifyAll简单介绍1.1 使用方法 + 为什么不是Thread类的方法1.2 什么时候加锁、什么时候释放锁?1.3 notify、notifyAll的区别2 两个比较经典的使用案例2.1 案例1 — ABCABC。。。三个线程...
wait和notify讲解
一个简单的线程同步机制,也能实例了解wait notify的使用,notify与notifyAll的区别
java多线程下wait和notify的作用
wait()、notify()和notifyAll()方法2---马克-to-win java视频
java多线程之wait,notify的用法([ 详解+实例 ]).
wait()、notify()和notifyAll()方法1---马克-to-win java视频
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
本篇文章是对java多线程 wait(),notify(),notifyAll()进行了详细的分析介绍,需要的朋友参考下