Java如何实现线程交替执行?

这是个比较基础但是面试常考的一个问题,用两道经典面试题来close这个话题吧。在Java中实现线程协作一般就是用wait/notify模式。

一.两个线程交替打印0~100的奇偶数

/*
 * 简单复习:
 * 1.wait和notify都是Object类的方法。
 * 2.wait和notify必须要在synchronized代码块中执行,否则会抛异常。
 */
public class WaitNotifyPrint {

    private static int count = 0;
    //两个线程竞争该对象锁
    private static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        new Thread(new TurningRunner(), "偶数").start();
        new Thread(new TurningRunner(), "奇数").start();
    }

    //1. 拿到锁直接就打印。
    //2. 打印完,唤醒其他线程,自己就休眠。
    static class TurningRunner implements Runnable {

        @Override
        public void run() {
            while (count <= 100) {
                synchronized (lock) {
                    //拿到锁就打印
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                    //打印完,唤醒其他线程
                    lock.notify();
                    //如果任务还没结束,就调用wait()让出当前的锁
                    if (count <= 100) {
                        try {
                            //自己休眠
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

注意交替打印奇偶数还可以用synchronized实现,感兴趣可以自行百度~

二.实现经典的生产者消费者模式

/* 
 * 场景描述:用EventStorage模拟仓库,Producer代表生产者,Consumer代表消费者,
 * 生产者和消费者共同对仓库进行协作。
 * 下面会有大量注释进行说明,放心阅读~
 */
public class ProducerConsumerModel {
    public static void main(String[] args) {
        //初始化仓库
        EventStorage eventStorage = new EventStorage();
        //用仓库初始化生产者
        Producer producer = new Producer(eventStorage);
        //用仓库初始化消费者
        Consumer consumer = new Consumer(eventStorage);
        //启动生产者和消费者
        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

class Producer implements Runnable {

    private EventStorage storage;

    public Producer(
            EventStorage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        //生产者往仓库中生产100个对象(此时消费者也在消费)
        for (int i = 0; i < 100; i++) {
            storage.put();
        }
    }
}

class Consumer implements Runnable {

    private EventStorage storage;

    public Consumer(
            EventStorage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        //消费者循环消费仓库中的对象(此时生产者也在生产)
        for (int i = 0; i < 100; i++) {
            storage.take();
        }
    }
}

class EventStorage {
    private int maxSize;
    //用Date来模拟对象
    private LinkedList storage;
    //注意看构造方法定义仓库大小为10,并且用LinkedList来存储对象
    public EventStorage() {
        maxSize = 10;
        storage = new LinkedList<>();
    }
    public synchronized void put() {
        //仓库满了就休眠
        while (storage.size() == maxSize) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //仓库没满就添加并通知消费者
        storage.add(new Date());
        System.out.println("仓库里有了" + storage.size() + "个产品。");
        notify();
    }
    public synchronized void take() {
        //仓库空了就休眠
        while (storage.size() == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //没空就取数据,poll方法代表检索并删除并通知生产者
        System.out.println("拿到了" + storage.poll() + ",现在仓库还剩下" + storage.size());
        notify();
    }
}

三.总结

wait/notify是比较底层的实现,现在一般都是用JDK封装好的一些工具类或框架,比如阻塞队列,线程协作工具类。但是这些工具万变不离其宗,了解本质才是根本。

你可能感兴趣的:(Java如何实现线程交替执行?)