多线程五-线程通信之wait与notify

wait与notify用于syncronized的线程间通信的一种,wait用来阻塞线程并释放锁,notify用来唤醒线程。他们与condition作用基本一致,但是由于syncronized为jdk实现,阅读源码有难度,所以通过了解其原理,用来帮助我们后续理解condition的源码。
可以通过下面一张图来理解:
syncronized.png
下面通过一个简单的生产者与消费者的例子来体会一下这两个API的用法
生产者代码:

package com.caozz.demo5.concurrent;

import java.util.Queue;

public class Producer implements Runnable{

    private Queue<String> bags;

    private int maxSize;

    public Producer(Queue<String> bags, int maxSize) {
        this.bags = bags;
        this.maxSize = maxSize;
    }

    @Override
    public void run(){
        int i = 0;
        while (true) {
            i++;
            synchronized (bags) {
                if (bags.size() >= maxSize) {
                    System.out.println("bags 满了");
                    try {
                        bags.wait();//满了则阻塞当前线程并释放
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("生产者生产: bag" + i);
                bags.add("bag" + i);
                bags.notify();//表示已经生产数据了,消费者可以消费了(消费者不一定能抢到锁)
            }
        }
    }

}

消费者代码:

package com.caozz.demo5.concurrent;

import java.util.Queue;

public class Consumer  implements Runnable{
    private Queue<String> bags;


    public Consumer(Queue<String> bags){
        this.bags = bags;
    }

    @Override
    public void run() {
        while (true) {
            //与生产者肯定是同一个对象,否则不是同一把锁就无法实现线程间通信了
            synchronized (bags) {
                if (bags.isEmpty()) {
                    System.out.println("bags 为空");
                    try {
                        bags.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
                String bag = bags.remove();
                System.out.println("消费者消费:" + bag);
                //如果生产者满了被阻塞,此时消费了所以必然可以继续生产
                //这里只是唤醒线程,但是生产者并不能马上执行,因为需要等到同步代码块执行完成,即monitorexit指令执行完成
                bags.notify();
            }
        }
    }
}

测试:

package com.caozz.demo5.controller;

import com.caozz.demo5.concurrent.Consumer;
import com.caozz.demo5.concurrent.Producer;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {
    public static void main(String[] args) throws InterruptedException {
//        Lock lock = new ReentrantLock(true);
//        lock.lock();
//        lock.unlock();
        Queue<String> bags = new LinkedList<>();
        int maxSize = 500;
        Producer producer = new Producer(bags, maxSize);
        Consumer consumer = new Consumer(bags);

        new Thread(producer).start();
        Thread.sleep(1);
        new Thread(consumer).start();
    }
}

部分执行结果:省略号省略得内容连续

消费者消费:bag183545
消费者消费:bag183546
消费者消费:bag183547
生产者生产: bag183572
生产者生产: bag183573
...
生产者生产: bag183580
消费者消费:bag183548
...
消费者消费:bag183580
bags 为空
生产者生产: bag183581
生产者生产: bag183582
消费者消费:bag183581
消费者消费:bag183582
bags 为空
生产者生产: bag183583
...
生产者生产: bag183591
消费者消费:bag183583
消费者消费:bag183584
欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!

posted @ 2024-09-15 22:18  东方欲晓_莫道君行早  阅读(32)  评论(0编辑  收藏  举报