wait 和 notify以及notifyAll
notify方法可以随机唤醒等待队列中等待同一共享资源的“一个”线程,使其退出等待队列进入可运行状态。
测试在调用notify方法之后并不会马上释放对象锁,而是在执行完同步方法或同步方法块的时候才会释放。
代码如下:
public class MyList { PRivate static List<String> list = new ArrayList<String>(); public static void add(){ list.add("sth"); } public static int getSize(){ return list.size(); }}main方法以及两个线程类如下:
public class Test { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); ThreadA ta = new ThreadA(lock); Thread tta = new Thread(ta); tta.start(); Thread.sleep(50); ThreadB tb = new ThreadB(lock); Thread ttb = new Thread(tb); ttb.start(); }}class ThreadA implements Runnable{ private Object mLock; public ThreadA(Object lock){ mLock = lock; } public void run() { synchronized (mLock) { if(MyList.getSize() != 5){ try { System.out.println("before wait"); mLock.wait(); System.out.println("after wait"); } catch (InterruptedException e) { e.printStackTrace(); } } } }}class ThreadB implements Runnable{ private Object mLock; public ThreadB(Object lock){ mLock = lock; } public void run() { synchronized (mLock) { for(int i = 0; i< 10; i++){ MyList.add(); if(MyList.getSize() == 5){ mLock.notify(); System.out.println("已发出notify通知"); } System.out.println("增加"+(i+1)+"条数据"); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("同步方法之外的方法"); }}打印结果如下:
before wait增加1条数据增加2条数据增加3条数据增加4条数据已发出notify通知增加5条数据增加6条数据增加7条数据增加8条数据增加9条数据增加10条数据after wait同步方法之外的方法可以看出2点:
最后说下 wait和sleep的区别,这也是面试经常面到的问题。
写个小栗子来证明结论2: 在MyList类中增加一个方法:
public synchronized void doSth(){ System.out.println("Thrad name : "+Thread.currentThread().getName()+" , begain doSth time : "+System.currentTimeMillis()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thrad name : "+Thread.currentThread().getName()+" , end doSth time : "+System.currentTimeMillis()); }测试main方法
MyList myList = new MyList(); ThreadC tc = new ThreadC(myList); tc.setName("C"); ThreadD td = new ThreadD(myList); td.setName("D"); tc.start(); td.start();ThreadC和ThreadD类如下:
class ThreadC extends Thread{ private MyList myList; public ThreadC(MyList mlist){ myList = mlist; } @Override public void run() { myList.doSth(); }}class ThreadD extends Thread{ private MyList myList; public ThreadD(MyList mlist){ myList = mlist; } @Override public void run() { myList.doSth(); }}结果如下:
Thrad name : C , begain doSth time : 1487647524673Thrad name : C , end doSth time : 1487647527674Thrad name : D , begain doSth time : 1487647527674Thrad name : D , end doSth time : 1487647530674可以看出线程C在调用sleep方法后并不会释放。
最后作点说明: 每个锁对象都有两个队列,就绪队列以及阻塞队列。就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程。一个线程被唤醒后,才会进入就绪队列,以等待CPU调度。反之一个线程被wait后就会进入阻塞队列,等待下一次唤醒。 也就是说一个线程被wait后会进入阻塞队列,待调用了 notify或notifyAll之后,该线程就会进入就绪队列。
新闻热点
疑难解答