java多线程之线程间的通信(wait,notify)

2019-09-28  本文已影响0人  不二不二熊
一、入门demo,实现经典的生产者消费者模型
/**
 * @author: localhost
 * @program: mySpringBoot
 * @description: 消费者
 * @create: 2019-09-06 13:16
 **/
@Slf4j
public class ConsumerRunabble implements Runnable {
    private List<Integer> list;

    public ConsumerRunabble(List<Integer> list) {
        this.list = list;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (list) {
                if (list.size() <=0) {
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("===消费者收到通知,开始消费数据===");
                Iterator<Integer> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Integer next = iterator.next();
                    if (next != null) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        log.info("消费了数据:{}", next);
                        iterator.remove();
                    }
                }
                System.out.println("====数据消费完毕,通知生产者生产数据==");
                list.notifyAll();
            }
        }
    }
}
/**
 * @author: localhost
 * @program: mySpringBoot
 * @description: 生产者
 * @create: 2019-09-06 13:23
 **/
@Slf4j
public class ProducerRunabble implements Runnable {
    private List<Integer> list;

    public ProducerRunabble(List<Integer> list) {
        this.list = list;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (list) {
                if (list.size() > 0) {
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //开始生产数据
                System.out.println("======收到通知,开始生产数据======");
                for (int i = 0; i < 3; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    list.add(i);
                    log.info("生产者添加了数据:{}", i);
                }
                list.notifyAll();
                System.out.println("====数据生产完毕,通知消费者消费数据===");
            }
        }
    }
}
/**
 * @author: localhost
 * @program: mySpringBoot
 * @description:
 * @create: 2019-09-06 13:29
 **/
public class TestDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        //推荐使用线程池创建,模拟测试暂时手动创建
        new Thread(new ProducerRunabble(list)).start();
        new Thread(new ConsumerRunabble(list)).start();
    }
}
二、关于通知等待机制

其实可以类比为人类世界的去医院排队挂号验血,首先你要去排队,然后等待,当有人通知你可以进行验血的时候你才去启动,其他时间都是等待状态。与sleep()不同的是,wait()会释放持有的锁。当被唤醒时,会重新去获取锁,但是不一定能马上获取到,这取决于cpu的分配。

另外,我强烈建议你在唤醒队列的时候,使用notifyAll()而不是notify()。打个比方,假设等待队列中有两个等待线程a和线程b,此时你需要唤醒线程b,使用notify()结果却唤醒了a线程,这是不值当的。

因为Java给我们提供了等待唤醒机制,因此在实际工作中们,对于某些使用轮询的地方,我们不妨将他替换成等待唤醒,这样可以节省资源。

上一篇下一篇

猜你喜欢

热点阅读