目录
wait & notify
之前学习过wait和notify,但是总是理不清楚,不太明白,今天整理一篇博客,
争取把wait和notify搞明白。
- wait和notify是Object的方法,而不是Thread的方法。
- Object的wait方法会导致当前线程陷入阻塞,直到其他线程调用了该Object的notify或者notifyAll方法才能将其唤醒,或者如果设置了阻塞时间,时间到了
自动唤醒。
- wait、notify必须要在同步方法中使用,必须持有同步方法的monitor的所有权。
- 当前线程执行了该对象的wait方法后,就会放弃该monitor的所有权并且进入与这个对象关联的wait set 中。在wait set可以等待被其他线程唤醒,重新持有monitor所有权。
写一个经典的生产者和消费者的例子:
/**
* @author: wang ming xin
* @create: 2019-01-12 13:00
*/
//生产饼干
public class MyBlockingQueue {
private int max = 10; //容量设置为10
//静态内部类 饼干
static class Cookie{
}
private LinkedList<Cookie> cookieQueue = new LinkedList<>();
public void offer(Cookie cookie){
synchronized (cookieQueue){
if(cookieQueue.size() >= max){
try {
System.out.println("装饼干的容器已经满了...");
cookieQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("做了一个新的饼干,热乎着呢...");
cookieQueue.addLast(cookie);
cookieQueue.notify();
}
}
public Cookie take(){
synchronized (cookieQueue){
if(cookieQueue.size() == 0){
try {
System.out.println("没饼干了,等待...");
cookieQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("买走一个饼干...");
Cookie cookie = cookieQueue.removeFirst();
cookieQueue.notify();
return cookie;
}
}
}
写一个测试类:
/**
* @author: wang ming xin
* @create: 2019-01-12 13:12
*/
public class CookieCustomer {
public static void main(String[] args){
MyBlockingQueue queue = new MyBlockingQueue();
new Thread(()->{
while (true){
try {
//模拟制作一个饼干消耗的时间
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
queue.offer(new MyBlockingQueue.Cookie());
}
},"生产者").start();
new Thread(()->{
while(true){
queue.take();
try {
//模拟吃一个饼干消耗的时间
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者").start();
}
}
运行效果:
只要容器没满,生产者就一直制造饼干,并通知消费者可以购买
wait VS sleep
wait和sleep也容器理解错误和使用错误,在这里顺便过一下
- 都可以让线程进入阻塞状态。
- wait是Object的方法,而sleep是Thread的方法。
- wait方法的执行必须在同步方法中进行,而sleep不需要。
- 在同步方法中执行sleep方法时,线程抱着monitor锁沉睡,而wait方法会直接放弃monitor的所有权。
另外还有一点就是可以不用Thread.sleep( ),
而用TimeUnit.SECONDS.sleep( ),比Thread.sleep( ) 功能更强大,编程更优雅
支持各种时间单位的slepp
java.util.concurrent.TimeUnit
notifyAll
最后了解下notifyAll
顾名思义和notify差不多,只是唤醒的是wait set中全部阻塞的线程,而notify只能唤醒wait set中的一个线程。
使用notifyAll改写阻塞队列,可以解决多线程(大于2个线程)通信数据不一致的问题,,
比如存在多个消费者或者多个生产者,
再使用notify就会出现问题
public class MyBlockingQueue1 {
private int max = 10; //容量设置为10
//静态内部类 饼干
static class Cookie{
}
private LinkedList<Cookie> cookieQueue = new LinkedList<>();
public void offer(Cookie cookie){
synchronized (cookieQueue){
while (cookieQueue.size() >= max){
try {
System.out.println("装饼干的容器已经满了...");
cookieQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("做了一个新的饼干,热乎着呢...");
cookieQueue.addLast(cookie);
cookieQueue.notifyAll();
}
}
public Cookie take(){
synchronized (cookieQueue){
while (cookieQueue.size() == 0){
try {
System.out.println("没饼干了,等待...");
cookieQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("买走一个饼干...");
Cookie cookie = cookieQueue.removeFirst();
cookieQueue.notifyAll();
return cookie;
}
}
}
现在模拟2个消费者
public class CookieCustomer {
public static void main(String[] args){
MyBlockingQueue1 queue = new MyBlockingQueue1();
new Thread(()->{
while (true){
try {
//模拟制作一个饼干消耗的时间
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
queue.offer(new MyBlockingQueue1.Cookie());
}
},"生产者").start();
new Thread(()->{
while(true){
queue.take();
try {
//模拟吃一个饼干消耗的时间
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者1").start();
new Thread(()->{
while(true){
queue.take();
try {
//模拟吃一个饼干消耗的时间
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"消费者2").start();
}
}
转载请注明:汪明鑫的个人博客 » wait & notify
说点什么
2 评论 在 "wait & notify"
因为wait和notify是Object的方法,所以每个对象都有这两个方法。线程同步代码中调用wait方法,是会进入当前同步监视器对象的等待队列(阻塞),notify & notifyAll只会唤醒同一同步监视器对象中的等待队列中的线程。
666,毛贺