java基础线程-wait+notify

来源:互联网 发布:2017年6月房地产数据 编辑:程序博客网 时间:2024/05/17 08:35
package common;/** * Created by shao on 2016/11/3. */public class ThreadTest implements Runnable{    int number=0;    private Object lock;    public ThreadTest(){        lock = new Object();    }    public Object getLock() {        return lock;    }    public void setLock(Object lock) {        this.lock = lock;    }    @Override    public void run() {        System.out.println(Thread.currentThread().getName() + " 我已开始运行了" );        synchronized(lock){            for (int i = 0; i < 5; i++) {                try {                    number++;                    Thread.sleep(1000);                    if(i==3){                        lock.wait();                    }                    System.out.println(Thread.currentThread().getName() + " " +i);                } catch (Throwable e) {                    System.out.println(e);                }            }        }        System.out.println(Thread.currentThread().getName() + " 我运行结束了" );    }    public static void main(String args[]) {        int number = 0;        ThreadTest tt=new ThreadTest();        try {            Thread th1 = new Thread(tt);            th1.setName("邵飞飞是高手");            th1.start();            Thread th2 = new Thread(tt);            th2.setName("高手");            th2.start();            Thread.sleep(10000);            System.out.println("锁的时间达到10秒");            synchronized(tt.getLock()){                tt.getLock().notify();            }        } catch (Throwable e) {            System.out.println(e);        }    }}


对象的wait()是让当前线程释放该对象Monitor锁并且进入访问该对象的等待队列,当前线程会进入挂起状态,等待操作系统唤起(notify)
挂起的线程重新获取对该对象的访问锁才能进入运行状态。因为自身已经挂起,所以已经挂起的线程无法唤醒自己,必须通过别的线程
告诉操作系统,再由操作系统唤醒。Monitor是不能被并发访问的(否则Monitor状态会出错,操作系统根据错误的状态调度导致系统错乱),
而wait和nofity 正是改变Monitor的状态(请参考 PV操作) 所以使用wait、notify方法时,必须对对象使用synchronized加锁,只有线程获
取对象的Monitor锁之后才能进行wait、notify操作否则将抛出IllegalMonitorStateException异常

结果分析:

1. 两个线程无序都开始,结果第三行看出来,邵飞飞是高手 先运行,又因为run中的for循环有synchronized锁所以,高手 线程就等待中了。一直运行到结果的第5行

2.  因为在在i==3时我加了一个wait()锁,所以这时候 邵飞飞是高手 线程进行等待中,释放了for循环的synchronized,这时候 高手 线程开始运行。高手 线程运行到 i=3时又运行了lock.wait()函数,高手 线程也进入了等待中。这时候main函数中的sleep(10000)运行完了,lock.notify()运行了,lock对象释放了,这时候 邵飞飞是高手线程得到这个解锁的lock,因为在notify之前,两个线程都进入了wait set 队列(队列:先进先出;栈:先进后出),这时notify运行,lock对象解锁,邵飞飞是高手 线程在synchronized等待队列的最前面,所以邵飞飞是高手 高手 在次先运行一直运行结束

3.  等 邵飞飞是高手 线程运行结束之后,高手 线程开始运行for循环的部分,可是之前lock对象wait()了两次,现在只notify()一次,而且也被 邵飞飞是高手 线程抢走了,所以 高手 线程现在中的lock还是wait等待中,所以 高手 线程 永远也运行不到i=3及以后的代码,且这个线程永远是等待中,没有结束(除非被java当作垃圾回收)

4.  如果将notify()方法改为 notifyAll(),那么在notifyAll()执行之后,lock对象没有再wait()了,所以运行notifyAll()将 高手 邵飞飞是高手 两个线程中的wait()都解锁了,所以最后 高手 线程也会运行完的



声明:一个Object对象wait了几次就对应notify几次。

        线程与线程之间是并行执行,单个线程内部的代码是串行执行的

       synchronized(T){},T中不管为什么对象,{}中的代码都是被锁住的。但是如果本实验中的synchronized(lock){}改为synchronized(this),就会抛出IllegalMonitorStateException异常

       Object.wait([time]);如果time为空的,即没有参数的,那要notify()才能打开锁。如果有参数的,即time!=null,那么不用notify()它也能在到达时间之后自己开锁,都都要在synchronized(Object){}的{}中

1 0
原创粉丝点击