您的位置:首页 > 编程语言 > Java开发

java notify,wait,notifyAll理解和实例(一)

2017-05-21 18:34 423 查看
通常可以使用synchronized和notify,notifyAll以及wait方法来实现线程之间的数据传递及控制。对于对象obj来说:

obj.wait():该方法的调用,使得调用该方法的执行线程(T1)放弃obj的对象锁并阻塞,直到别的线程调用了obj的notifyAll方法、或者别的线程调用了obj的notify方法且JVM选择唤醒(T1),被唤醒的线程(T1)依旧阻塞在wait方法中,与其它的线程一起争夺obj的对象锁,直到它再次获得了obj的对象锁之后,才能从wait方法中返回。(除了notify方法,wait还有带有时间参数的版本,在等待了超过所设时间之后,T1线程一样会被唤醒,进入到争夺obj对象锁的行列;另外中断可以直接跳出wait方法)

obj.notify():该方法的调用,会从所有正在等待obj对象锁的线程中,唤醒其中的一个(选择算法依赖于不同实现),被唤醒的线程此时加入到了obj对象锁的争夺之中,然而该notify方法的执行线程此时并未释放obj的对象锁,而是离开synchronized代码块时释放。因此在notify方法之后,synchronized代码块结束之前,所有其他被唤醒的,等待obj对象锁的线程依旧被阻塞。
obj.notifyAll():与notify的区别是,该方法会唤醒所有正在等待obj对象锁的线程。(不过同一时刻,也只有一个线程可以拥有obj的对象锁)

要注意的是,wai,notify以及notifyAll方法的调用必须在相应的synchronized代码块之中。

编号方法描述
1
public void wait()
使当前线程等到另一个线程调用
notify()
方法。
2
public void notify()
唤醒在此对象监视器上等待的单个线程。
3
public void notifyAll()
唤醒所有在同一个对象上调用
wait()
的线程。
public class Main {
public static void main(String[] args) {
MThread mThread = new MThread();
Thread thread = new Thread(mThread);
thread.start();

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mThread.assign();
}
}
import java.util.Date;

/**
* Created by liuyazhou on 2017/5/21.
*/
public class MThread implements Runnable {
public synchronized void assign() {
System.out.println("MThread assign Date1:"+new Date());
this.notify();
System.err.println("out of notifyAll");

try {
Thread.sleep(10000);//修改这个时间会发现更多
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MThread assign Date2:"+new Date());
}

public synchronized void await() throws InterruptedException {
System.out.println("MThread await Date1:"+new Date());
this.wait(5000);
System.err.println("out of wait");
System.out.println("MThread await Date2:"+new Date());
}

@Override
public void run() {
try {
System.out.println("MThread is running...");
await();
} catch (InterruptedException e) {
}
}

}
MThread is running...
MThread await Date1:Sun May 21 18:18:36 CST 2017
out of notifyAll
MThread assign Date1:Sun May 21 18:18:37 CST 2017
MThread assign Date2:Sun May 21 18:18:47 CST 2017
MThread await Date2:Sun May 21 18:18:47 CST 2017
out of wait

下面来分析输出的结果:

start后进入await方法,需要等待5s,但是同时1s后开始进入唤醒,虽然执行了notify但是assign是同步方法,所以即使5s过完了,需要对象锁,但是也要等10s后释放对象锁才行。

第二个例子:

public class MThread implements Runnable {
public synchronized void assign() {
System.out.println("MThread assign Date1:"+new Date());
this.notify();
System.err.println("out of notifyAll");

try {
Thread.sleep(3000);//修改这个时间会发现更多
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MThread assign Date2:"+new Date());
}

public synchronized void await() throws InterruptedException {
System.out.println("MThread await Date1:"+new Date());
this.wait(5000);
System.err.println("out of wait");
System.out.println("MThread await Date2:"+new Date());
}

@Override
public void run() {
try {
System.out.println("MThread is running...");
await();
} catch (InterruptedException e) {
}
}
}
//MThread is running...
//MThread await Date1:Sun May 21 18:28:23 CST 2017
//out of notifyAll
//MThread assign Date1:Sun May 21 18:28:24 CST 2017
//MThread assign Date2:Sun May 21 18:28:27 CST 2017
//out of wait
//MThread await Date2:Sun May 21 18:28:27 CST 2017
Main.java不变,把notify所在的等待时间设为3s,加上原来的1s,总共是4s,所以即使没有到5s,也会被唤醒。

同时如果wait()方法里没有参数,也会被nofity或notifyAll唤醒;如果有时长参数即使不用nofity或notifyAll唤醒,到时间后也会得到对象锁,自己唤醒

第三个例子:

public class Main {
public static void main(String[] args) {
MThread mThread = new MThread();
Thread thread = new Thread(mThread);
thread.start();

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//        mThread.assign();
}
}
//MThread is running...
//MThread await Date1:Sun May 21 18:39:07 CST 2017
//MThread await Date2:Sun May 21 18:39:12 CST 2017
//out of wait
修改后的Mthread.java不变,把assign注释掉,5s后自动唤醒;如果wait不设置时长参数,会一直等待下去......
转自:
https://my.oschina.net/fengheju/blog/169695 http://www.yiibai.com/java_concurrency/concurrency_interthread_communication.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  notify wait notifyAll