wait/notify:
wait()使线程停止,notify使wait状态的线程继续执行。
wait()是Object类的方法,该方法用来将线程置入“预执行队列”,并在wait()方法处停止执行,直到接到通知或被中断为止。调用wait()方法必须要获得对象的锁,即只能在同步方法或同步块中调用wait()方法。调用wait()方法后,对象的锁被当前线程释放。
notify()也是在同步块或同步方法中调用,调用前必须获得对象的锁,该方法用来通知那些等待该对象的锁的其它线程。如果有多个线程等待,则挑选一个wait()状态线程,对其发出通知,如果没有线程等待,则该命令被忽略。在该notify()方法所在的synchronized块或方法执行完毕后,才使被挑选的线程获取该对象的锁。
注意:如果调用wait() 或notify() 没有持有对象的锁,会抛出IlegalMonitorStateException异常。
1 package multiMethod.waitNotify; 2 3 import java.util.LinkedList; 4 import java.util.List; 5 import java.util.concurrent.atomic.AtomicInteger; 6 7 public class MyList { 8 private List<String> list = new LinkedList<String>(); 9 private AtomicInteger count = new AtomicInteger(0); 10 private int maxSize, minSize; 11 private Object lock = new Object(); 12 13 public MyList(int maxSize, int minSize) { 14 this.maxSize = maxSize; 15 this.minSize = minSize; 16 } 17 18 public void add() { 19 synchronized (lock) { 20 try { 21 if (getSize() == maxSize) { 22 lock.wait(); 23 } 24 } catch (Exception e) { 25 } 26 list.add("hello"); 27 System.out.println("add ..."); 28 count.incrementAndGet(); 29 lock.notify(); 30 } 31 } 32 33 public void take() { 34 synchronized (lock) { 35 try { 36 if (getSize() <= minSize) { 37 lock.wait(); 38 } 39 } catch (Exception e) { 40 // TODO: handle exception 41 } 42 list.remove(count.get()-1); 43 System.out.println("take()......."); 44 this.count.decrementAndGet(); 45 lock.notify(); 46 } 47 } 48 49 public int getSize() { 50 return count.get(); 51 } 52 53 public static void main(String[] args) { 54 MyList queue = new MyList(6, 3); 55 Thread threadA = new Thread(new Runnable() { 56 @Override 57 public void run() { 58 while (true) { 59 queue.add(); 60 } 61 } 62 }); 63 Thread threadB = new Thread(new Runnable() { 64 65 @Override 66 public void run() { 67 while (true) { 68 queue.take(); 69 } 70 } 71 }); 72 73 Thread threadC = new Thread(new Runnable() { 74 75 @Override 76 public void run() { 77 while (true) { 78 System.out.println((queue.count)); 79 } 80 } 81 }); 82 83 threadB.start(); 84 threadA.start(); 85 threadC.start(); 86 } 87 }
每个锁对象有两个队列,一个就绪队列,一个阻塞队列。就绪队列中线程已被唤醒,等待获得cpu,阻塞队列执行了wait(),等待被唤醒。
需要注意的是:
1. notify()通知过早,线程不会被唤醒,因为wait()后于notify()执行。
2. wait等待条件发生了变化,线程也不会被唤醒。
3. 唤醒同类,线程陷入假死。如:生产者唤醒生产者,消费者唤醒消费者。