Fork me on GitHub

【面试题】关于线程交替的面试题

线程交替打印的题经常出现,总结一下:

一、两个线程交替打印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();
                        }
                    }
                }
            }
        }
    }
}

二、生产者消费者

/* 
 * 用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<Date> 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();
    }
}

三、交替打印ABC

方法一、synchronized

public class ABC {
    public static class ThreadPrinter implements Runnable {
        private String name;
        private Object prev;
        private Object self;
        private ThreadPrinter(String name,Object prev,Object self){
            this.name=name;
            this.prev=prev;
            this.self=self;
        }

        @Override
        public void run() {
            while (true){
                synchronized (prev){
                    synchronized (self){
                        System.out.println(name);
                        self.notifyAll();
                    }
                    try{
                        prev.wait();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }

            }
        }

        public static void main(String[] args) throws InterruptedException {
            Object a = new Object();
            Object b = new Object();
            Object c = new Object();

            ThreadPrinter pa=new ThreadPrinter("A",c,a);
            ThreadPrinter pb=new ThreadPrinter("B",a,b);
            ThreadPrinter pc=new ThreadPrinter("C",b,c);
            //保证ABC顺序执行
            new Thread(pa).start();
            Thread.sleep(10);
            new Thread(pb).start();
            Thread.sleep(10);
            new Thread(pc).start();
            Thread.sleep(10);

        }
    }
}

方法二、ReentrantLock

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

public class ABC2 {
    private static Lock lock= new ReentrantLock();
    private static int state=0;
    static class ThreadA extends Thread{
        @Override
        public void run() {
            while(true) {
                try {
                    lock.lock();
                    while (state % 3 == 0) {
                        System.out.println("A");
                        state++;
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    static class ThreadB extends Thread{
        @Override
        public void run() {
            while(true) {
                try {
                    lock.lock();
                    while (state % 3 == 1) {
                        System.out.println("B");
                        state++;
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    static class ThreadC extends Thread{
        @Override
        public void run() {
            while(true) {
                try {
                    lock.lock();
                    while (state % 3 == 2) {
                        System.out.println("C");
                        state++;
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    public static void main(String[] args) {
        new ThreadA().start();
        new ThreadB().start();
        new ThreadC().start();
    }
}

方法三、信号量

public class ABC3 {
    private static Semaphore A =new Semaphore(1);
    private static Semaphore B =new Semaphore(0);
    private static Semaphore C =new Semaphore(0);

    static class ThreadA extends Thread{
        @Override
        public void run() {
            try {
                while(true){
                    A.acquire();
                    System.out.println("A");
                    B.release();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    static class ThreadB extends Thread{
        @Override
        public void run() {
            try {
                while(true){
                    B.acquire();
                    System.out.println("B");
                    C.release();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    static class ThreadC extends Thread{
        @Override
        public void run() {
            try {
                while(true){
                    C.acquire();
                    System.out.println("C");
                    A.release();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        new ThreadA().start();
        new ThreadB().start();
        new ThreadC().start();
    }
}
posted @ 2021-03-16 10:26  kelexin  阅读(93)  评论(0编辑  收藏  举报