zoukankan      html  css  js  c++  java
  • 面试之多线程交替输出

    简述

      面试中常常被问到多线程交替输出数字或字母序列的问题,例如AB两个线程交替输出1到100。三个线程交替输出abcabcabc...等

    wait notify实现3线程交替输出abc

      我们首先抽象出一个用于打印字母的类:

    package ThreadTest.testOut;
    
    public class SyncWaitNotify {
        int flag;
        int loopNumber;
    
        public SyncWaitNotify(int flag, int loopNumber) {
            this.flag = flag;
            this.loopNumber = loopNumber;
        }
    
        public void print(int waitFlag,int nextFlag,String str){
            synchronized (this){
                while(waitFlag != nextFlag){
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(str);
                flag = nextFlag;
                this.notifyAll();
            }
        }
    
    }

      需要注意我们这里用整形flag的123代表abc,当前的flag不等于等待的flag时,将会进入等待队列等待。

      当被唤醒后则则会更新标记并唤醒其余线程进行输出,线程运行代码:

    package ThreadTest.testOut;
    
    public class TestABC {
        public static void main(String[] args) {
            SyncWaitNotify syncWaitNotify = new SyncWaitNotify(1, 5);
            new Thread(() -> {
                syncWaitNotify.print(1, 2, "a");
            }).start();
            new Thread(() -> {
                syncWaitNotify.print(2, 3, "b");
            }).start();
            new Thread(() -> {
                syncWaitNotify.print(3, 1, "c");
            }).start();
        }
    }

     await singal实现交替输出abc

      这个和wait notify不同之处在于,wait notify一唤醒就唤醒全部,醒来了再去判断自己该不该执行任务,不该的话就继续wait。而await singal有三个condiction,每个线程完成任务后可以知道该唤醒哪一个线程

    package ThreadTest.testOut;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class TestABC2 {
        public static void main(String[] args) throws InterruptedException {
            AwaitSignal awaitSignal = new AwaitSignal(5);
            Condition a = awaitSignal.newCondition();
            Condition b = awaitSignal.newCondition();
            Condition c = awaitSignal.newCondition();
            new Thread(()->{
                awaitSignal.print("a",a,b);
            }).start();
            new Thread(()->{
                awaitSignal.print("b",b,c);
            }).start();
            new Thread(()->{
                awaitSignal.print("c",c,a);
            }).start();
            Thread.sleep(1000);
            awaitSignal.lock();
            try{
                a.signal();
            }
            finally {
                awaitSignal.unlock();
            }
        }
    }
    
    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();
                try{
                    current.await();
                    System.out.print(str);
                    next.signal();//唤醒下一间休息室
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    unlock();
                }
            }
        }
    }

    park和unpark实现交替输出abc

      我们还可以使用park unpark完成此任务,这种实现方式是以线程为单位的,所以代码更加简洁

    package ThreadTest.testOut;
    
    import java.util.concurrent.locks.LockSupport;
    
    public class TestABC3 {
    
        static Thread t1;
        static Thread t2;
        static Thread t3;
    
        public static void main(String[] args) {
            ParkUnpark parkUnpark = new ParkUnpark(5);
            t1 = new Thread(()->{
                parkUnpark.print("a",t2);
            });
            t2 = new Thread(()->{
                parkUnpark.print("b",t3);
            });
            t3 = new Thread(()->{
                parkUnpark.print("c",t1);
            });
            t1.start();
            t2.start();
            t3.start();
            LockSupport.unpark(t1);
        }
    }
    
    class ParkUnpark {
        private int loopNumber;
    
        public ParkUnpark(int loopNumber) {
            this.loopNumber = loopNumber;
        }
    
        public void print(String str,Thread next){
            for(int i=0;i<loopNumber;i++){
                LockSupport.park();
                System.out.print(str);
                LockSupport.unpark(next);
            }
        }
    }

     

      

    一点一点积累,一点一点蜕变!
  • 相关阅读:
    1074 食物链 (并查集)
    2832 6个朋友
    病毒 (拓扑)
    4735 烦人的幻灯片 (拓扑)
    JavaScript中变量的LHS引述和RHS引用
    td自动换行
    SQL Server 中的 NOLOCK 到底是什么意思?
    jQuery中遇到的坑
    jQuery中attr()函数 VS prop()函数
    Javascript刷新页面的几种方法
  • 原文地址:https://www.cnblogs.com/qq2210446939/p/15121165.html
Copyright © 2011-2022 走看看