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

来源:互联网 发布:java调用软件api接口 编辑:程序博客网 时间:2024/05/18 15:56
通常可以使用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代码块之中。

编号方法描述1public void wait()使当前线程等到另一个线程调用notify()方法。2public void notify()唤醒在此对象监视器上等待的单个线程。3public 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 2017out of notifyAllMThread assign Date1:Sun May 21 18:18:37 CST 2017MThread assign Date2:Sun May 21 18:18:47 CST 2017MThread await Date2:Sun May 21 18:18:47 CST 2017out 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