基本前提知识:
一:Object/wait(), notify(), notifyAll()
1:wait() 方法暂停当前线程,并立即释放对象锁;
2:notify()/notifyAll() 方法唤醒其他等待该对象锁的线程,并在执行完同步代码块中的后续步骤后,释放对象锁
3:notify()和notifyAll()的区别在于:
notify只会唤醒其中一个线程,
notifyAll则会唤醒全部线程。
至于notify会唤醒哪个线程,是由线程调度器决定的。
例子:
public class TestWaitAndnotify { public static void main(String[] args) { demo2(); } public static void demo2 () { final Object lock = new Object(); Thread A = new Thread(new Runnable(){ @Override public void run() { System.out.println("INFO: A 等待锁 "); synchronized (lock) { System.out.println("INFO: A 得到了锁 lock"); System.out.println("A1"); try { System.out.println("INFO: A 准备进入等待状态,放弃锁 lock 的控制权 "); lock.wait();//挂起线程A 放弃锁 lock 的控制权 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("INFO: 有人唤醒了 A, A 重新获得锁 lock"); System.out.println("A2"); System.out.println("A3"); } } }); Thread B = new Thread(new Runnable() { @Override public void run() { System.out.println("INFO: B 等待锁 "); synchronized (lock) { System.out.println("INFO: B 得到了锁 lock"); System.out.println("B1"); System.out.println("B2"); System.out.println("B3"); System.out.println("INFO: B 打印完毕,调用 notify 方法 "); lock.notify(); // notify()方法唤醒正在等待lock锁的线程A System.out.println("线程 B do notify method 完毕"); } } }); A.start(); B.start(); } }
输出:
题外话: notify()方法唤醒等待锁对象的其他线程,这个notify()方法需要先执行完自己线程的后续代码,才会接着执行被唤醒的那个线程的代码,修改上面的例子看一下:
public class TestWaitAndnotify { public static void main(String[] args) { demo2(); } public static void demo2 () { final Object lock = new Object(); Thread A = new Thread(new Runnable(){ @Override public void run() { System.out.println("INFO: A 等待锁 "); synchronized (lock) { System.out.println("INFO: A 得到了锁 lock"); System.out.println("A1"); try { System.out.println("INFO: A 准备进入等待状态,放弃锁 lock 的控制权 "); lock.wait();//挂起线程A 放弃锁 lock 的控制权 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("INFO: 有人唤醒了 A, A 重新获得锁 lock"); System.out.println("A2"); System.out.println("A3"); } } }); Thread B = new Thread(new Runnable() { @Override public void run() { System.out.println("INFO: B 等待锁 "); synchronized (lock) { System.out.println("INFO: B 得到了锁 lock"); System.out.println("B1"); System.out.println("B2"); System.out.println("B3"); System.out.println("INFO: B 打印完毕,调用 notify 方法 "); lock.notify(); // notify()方法唤醒正在等待lock锁的线程A try { Thread.sleep(10000); // 睡眠10秒钟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程 B do notify method 完毕"); } } }); A.start(); B.start(); } }
打印完:INFO: B 打印完毕,调用 notify 方法 后面等待了10秒钟才开始执行。wait()方法是要等待notify()后续的代码才能开始。
生产者消费者例子:
import java.util.LinkedList; import java.util.Queue; public class ProducerAndConsumer { private final int MAX_LEN = 3; private Queue<Integer> queue = new LinkedList<Integer>(); class Producer extends Thread { @Override public void run() { producer(); } private void producer() { while(true) { synchronized (queue) { if(queue.size() == MAX_LEN) { System.out.println("当前队列满"); queue.notify(); try { queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.add(1); queue.notify(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("生产者又生产一条任务,当前队列长度为" + queue.size()); } } } } class Consumer extends Thread { @Override public void run() { consumer(); } private void consumer() { while(true) { synchronized (queue) { if(queue.size() == 0) { System.out.println("当前队列为空"); queue.notify(); try { queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.poll(); queue.notify(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费者消费了一条任务,当前队列长度为" + queue.size()); } } } } public static void main(String[] args) { ProducerAndConsumer pac = new ProducerAndConsumer(); Producer producer = pac.new Producer(); Consumer consumer = pac.new Consumer(); producer.start(); consumer.start(); } }
一:Lock/condition/await(), signal(), signalAll()
import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ProducerAndConsumer1 { private final int MAX_LEN = 3; private Queue<Integer> queue = new LinkedList<Integer>(); final Lock lock = new ReentrantLock(); final Condition producerSignal = lock.newCondition(); final Condition consumerSignal = lock.newCondition(); class Producer extends Thread { @Override public void run() { producer(); } private void producer() { while(true) { lock.lock(); try { if(queue.size() == MAX_LEN) { System.out.println("当前队列满"); try { consumerSignal.signal(); producerSignal.await(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.add(1); consumerSignal.signal(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("生产者生产了一条任务,当前队列长度为" + queue.size()); } finally { lock.unlock(); } } } } class Consumer extends Thread { @Override public void run() { consumer(); } private void consumer() { while(true) { lock.lock(); try { if(queue.size() == 0) { System.out.println("当前队列为空"); try { producerSignal.signal(); consumerSignal.await(); } catch (InterruptedException e) { e.printStackTrace(); } } queue.poll(); producerSignal.signal(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费者消费了一条任务,当前队列长度为" + queue.size()); } finally { lock.unlock(); } } } } public static void main(String[] args) { ProducerAndConsumer1 pac = new ProducerAndConsumer1(); Producer producer = pac.new Producer(); Consumer consumer = pac.new Consumer(); producer.start(); consumer.start(); } }
分析: 这里共享的变量是queue,生产者消费者都需要修改这个queue,为了保证安全,需要一个个的来,用lock,lock()就保证了每次只有一个线程来操作queue;
在生产和消费的时候,需要关心queue.size()的大小,如果满了,就不能生产,这里用了producerSignal.await(),让生产者放弃锁,去等待消费者去消费,consumerSignal.signal()去唤醒消费者去消费,如果空了,就不能消费, 这里用consumerSignal.await(),让消费者放弃锁,去等待生产者去生产,producerSignal.signal()去唤醒生产者去生产。