当前位置 博文首页 > Ocean曈的博客:一道面试题:两个线程,一个线程打印数字123456

    Ocean曈的博客:一道面试题:两个线程,一个线程打印数字123456

    作者:[db:作者] 时间:2021-06-21 12:40

    解题思路:
    在我看来要实现两个线程交替的打印,
    1.t1线程,打印数字1,然后唤醒t2线程,
    2.t1线程自己睡眠
    3.t2线程打印字母,A,然后唤醒t1线程

    上述步骤重复执行

    首先用** LockSupport.unpark() LockSupport.park()**的方案来实现,t1、t2 线程必须相互持有,实现代码如下:

    public class Test6 {
        static String s1 = "123456";
        static String s2 = "ABCDEFG";
    
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = null;
            Thread t2 = null;
            MyRunable myRunable2 = new MyRunable();
            MyRunable myRunable1 = new MyRunable();
            t1 =  new Thread(myRunable2);
            t2 =  new Thread(myRunable1);
            myRunable2.setOther(t2);
            myRunable2.setS(s2);
            myRunable1.setOther(t1);
            myRunable1.setS(s1);
            t2.start();
            Thread.sleep(10);
            t1.start();
        }
    
        static class MyRunable implements Runnable{
            private Thread other;
            private String s;
    
            public void setOther(Thread other) {
                this.other = other;
            }
    
            public void setS(String s) {
                this.s = s;
            }
    
            @Override
            public void run() {
                for (int i = 0; i < s.length(); i++) {
                    System.out.print(s.charAt(i));
                    LockSupport.unpark(other);
                    LockSupport.park();
                }
            }
        }
    }
    

    这个方案,就是两个线程互相持有,线程的频繁挂起,阻塞,比较消耗系统资源。因为这里其实只是少量的打印,其实看不出什么影响,无所谓啦。

    然后是第二种实现方案,用Synchronize+ wait() + notifyAll(), 实现代码如下:

    public class Test8 {
        static String s1 = "123456";
        static String s2 = "ABCDEFG";
    
        public static void main(String[] args) throws InterruptedException {
    
            Object lock1 = new Object();
            MyRunable r1 = new MyRunable(lock1, s1);
            MyRunable r2 = new MyRunable(lock1, s2);
    
            Thread t1 = new Thread(r1);
            Thread t2 = new Thread(r2);
    
            t1.start();
            t2.start();
            t1.join();
            t2.join();
        }
    
        static class MyRunable implements Runnable {
    
            private Object mylock;
            private String s;
    
            public MyRunable(Object mylock, String s) {
                this.mylock = mylock;
                this.s = s;
            }
    
            @Override
            public void run() {
                synchronized (mylock) {
                    for (int i = 0; i < s.length(); i++) {
                        System.out.println(s.charAt(i));
                        try {
                            mylock.notifyAll();
                            mylock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    

    这个方案就是两个线程持有了相同的一个object,对同一个objeck加锁。这样两个线程就不会互相持有了,只是持有了同样一个加锁对象。并且Synchronize加锁的效率,是一个锁升级的过程,在争抢不激烈的过程中,应该是一直是自旋锁的一个样子,不会因为调度系统线程资源的而浪费效率。所以,情况应该是好一些。

    最后还有一种实现方案:ReentrantLock+ Condition + await() + signal() 代码如下:

    public class Test9 {
    
        static String s1 = "1234567";
        static String s2 = "ABCDEFG";
        public static void main(String[] args) {
            Lock lock = new ReentrantLock();
            Condition condition1 = lock.newCondition();
            Condition condition2 = lock.newCondition();
            Runnable r1 = new TestRunable(lock,condition1,condition2,s1);
            Runnable r2 = new TestRunable(lock,condition2,condition1,s2);
            new Thread(r1).start();
            new Thread(r2).start();
    
        }
    
       static class TestRunable implements Runnable{
            Lock lock;
            Condition condition;
           Condition otherCondition;
           String s;
    
           public TestRunable(Lock lock, Condition condition, Condition otherCondition, String s) {
               this.lock = lock;
               this.condition = condition;
               this.otherCondition = otherCondition;
               this.s = s;
           }
    
           @Override
            public void run() {
                lock.lock();
                for (int i = 0; i < s.length(); i++) {
                    System.out.println(s.charAt(i));
                    otherCondition.signalAll();
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
               otherCondition.signalAll();
                lock.unlock();
            }
        }
    }
    

    ReentrantLock 底层的实现 其实也是LockSupport.park(),所以就不过多赘述了。这题的解题思路方案大致就是这么多了。当然,可能还有其他更加有效,写起来更加优美的方案,欢迎大家留言,一起讨论,进步!!!