经典多线程题目

发布时间 2023-10-15 15:15:46作者: 求知律己

1.三种线程按顺序执行

public class Test1 {
//    private static Logger log = Logger.getLogger(Test2.class);

    public static void main(String[] args) throws InterruptedException {
        //创建三个线程按照线程a,b,c执行
        Thread a = new PrintThread();
        Thread b = new PrintThread();
        Thread c = new PrintThread();
        a.setName("Thread-a");
        b.setName("Thread-b");
        c.setName("Thread-c");

        a.start();
        a.join();

        b.start();
        b.join();

        c.start();
        c.join();

    }

    public static class PrintThread extends Thread{

        @Override
        public void run() {
            super.run();
            System.out.println(Thread.currentThread().getName());
        }
    }
}
按序打印

  通过join()方法使得哪个线程调用join()方法,哪个线程执行完才能执行后续线程

2.两个线程轮流打印数字,直到100

public class Test2 {

    private static final Object lock = new Object();
    private static int count = 0;

    public static void main (String[] args) {
        //满足条件进入计算,可使得其他线程满足计算后的条件,不满足则等待
        new Thread(new PrintThread(0), "a").start();
        new Thread(new PrintThread(1), "b").start();
    }

    static class PrintThread implements Runnable{

        private int threadId;

        private PrintThread(int threadId){
            this.threadId = threadId;
        }
        @Override
        public void run() {
            synchronized (lock){
                while(count <= 100){
                    if(count%2 == threadId){//条件判断,结合wait和notifyAll
                        log.info(Thread.currentThread().getName()+"------"+count);
                        count++;
                        lock.notifyAll();
                    }else{
                        try {
                            lock.wait();
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
数字交替打印

  通过加锁的方式保证线程同步访问共享资源,通过条件变量调用notifyAll()方法获取锁通知线程执行,调用wait方法释放锁进入等待状态

3.交替打印ABC

public class Test3 {

    public static void main(String[] args) {
        AwaitSignal as = new AwaitSignal(5);
        //休息室
        Condition a = as.newCondition();
        Condition b = as.newCondition();
        Condition c = as.newCondition();
        //
        new Thread(() -> {
            as.print("A", a, b);
        }).start();
        new Thread(() -> {
            as.print("B", b, c );
        }).start();
        new Thread(() -> {
            as.print("C", c, a);
        }).start();

        as.lock();
        try{
            System.out.println("开始...");
            a.signal();//需要主线程主动唤醒a线程
        }finally {
            as.unlock();
        }
    }

    //
    static class AwaitSignal extends ReentrantLock {
        private int loopNumber;

        public AwaitSignal(int loopNumber){
            this.loopNumber = loopNumber;
        }

        //参数1 打印内容,参数2 当前休息室,参数3:下一间休息室
        public void print(String str, Condition current, Condition next){
            for (int i = 0; i < loopNumber; i++) {
                lock();//继承ReentrantLock锁手动加锁,锁住一个休息室
                try {
                    current.await();//休息室等待
                    System.out.print(str);
                    next.signal();//进入下一个休息室
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    unlock();
                }
            }
        }
    }

}
交替打印ABC

  通过继承ReentrantLock类来对字符按照顺序打印,其中包含两个Condition(休息等待区),一个当前Condition,另一个下一个Condition。只有前一个执行完后通过notifyAll()方法获取锁通知下一个进行。

4.生产者消费者模式

public class Test4 {
    Logger logger = LoggerFactory.getLogger(ProducerAndCustomerTest.class);
    public static void main(String[] args) {
        MessageQueue queue = new MessageQueue(2);
        //创建三个生产者生产消息
        for (int i = 0; i < 3 ; i++) {
            int id = i;
            new Thread(() ->{
                queue.put(new Message(id, "值:"+id));
            }, "生产者" + i).start();
        }


        new Thread(() -> {
            while(true){
                try {
                    Thread.sleep(1);
                    queue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"消费者").start();
    }
}

//消息队列类,java线程之间通信
class MessageQueue{
    Logger logger = LoggerFactory.getLogger(MessageQueue.class);
    //消息队列集合
    private LinkedList<Message> list = new LinkedList<>();
    //队列容量
    private int capacity;

    public MessageQueue(int capacity) {
        this.capacity = capacity;
    }

    //获取消息
    public Message take(){
        //检查对象是否为null
        synchronized (list){
            while(list.isEmpty()){
                try {
                    logger.info("队列为空,消费者等待消息生产");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //从队列头部获取消息返回
            Message message = list.removeFirst();
            logger.info("已消费信息 {}", message);
            //消费完通知
            list.notifyAll();
            return message;
        }
    }

    //存入消息
    public void put(Message message){
        synchronized (list){
            //检查队列是否已满
            while (list.size() == capacity){
                try {
                    logger.info("队列已满,生产者线程等待");
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //将消息加入队列尾部
            list.addLast(message);
            logger.info("已生产信息 {}", message);
            list.notifyAll();//生产完通知
        }
    }
}


final class Message{//安全
    private int id;
    private Object value;

    public Message(int id, Object value) {
        this.id = id;
        this.value = value;
    }

    public int getId() {//只有读安全,无法改变值
        return id;
    }

    public Object getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value=" + value +
                '}';
    }
}
提供者和消费者模式

  创建两类线程,一类生产者线程,另一类消费者线程。通过生产者线程生产消息并加入消息队列中,另一类消费者线程从消息队列中取出消息消费。通过消息队列的take()判断当消息集合为空时调用wait等待生产者生产,不为空时从消息集合取消息,并通过notifyAll()方法通知生产者消息消费完。通过消息队列的put()判断当消息集合为满时调用wait等待消费者,不满时向消息集合加入消息,并通过notifyAll()方法通知生产者消费消息。