• wait-notify模型面试题


    一道面试题:

    启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4,5…100

    错误实现1:

    public class NotifyErrorTest {
        private int i = 1;
    
        Thread t1 = new Thread(){
    
            @Override
            public void run() {
                while (true) {
                    synchronized (this) {
                        notify();
                        if (i <= 100) {
                            System.out.println(currentThread().getName() + ":" + i);
                            i++;
                            try {
                                wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        };
    
        Thread t2 = new Thread(){
    
            @Override
            public void run() {
                while (true) {
                    synchronized (this) {
                        notify();
                        if (i <= 100) {
                            System.out.println(currentThread().getName() + ":" + i);
                            i++;
                            try {
                                wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        };
    
        public static void main(String[] args){
            NotifyErrorTest test = new NotifyErrorTest();
    
            test.t1.start();
            test.t2.start();
        }
    }
    

    结果:

    Thread-0:1
    Thread-1:1
    

    打印出这两个后,线程就一直被挂起了。为什么会这样呢。
    先不考虑这种难看的重复代码需不需要重构,本身代码就有问题,虽然看起来都用了this,但是其实两个this所表示的含义不同,我们两个线程里面加上如下代码

    System.out.println(this.getClass());
    

    会发现打印出

    class pers.marscheng.thread.NotifyErrorTest$1
    class pers.marscheng.thread.NotifyErrorTest$2
    

    原来两个this不是同一个对象,匿名类会生成新的对象,所以导致两个线程获取的monitor锁是不同的。这就导致wait()方法调用之后,两个线程都被挂起,但是再也没人能把他们唤醒,而且由于锁不同,两个线程都同时执行了,打印出的都是1。

    正确实现:

    public class NotifyTest implements Runnable {
        int i = 1;
    
    
        public static void main(String[] args) {
            NotifyTest test = new NotifyTest();
            Thread t1 = new Thread(test);
            Thread t2 = new Thread(test);
    
            t1.start();
            t2.start();
    
    
        }
    
        @Override
        public void run() {
            while (true) {
                synchronized (this) {
                    this.notify();
                    if (i <= 100) {
                        String threadName = Thread.currentThread().getName();
                        System.out.println(threadName + ":" + i);
                        i++;
                        try {
                            this.wait();
    
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    

    通过condition实现:

    public class ConditionTest implements Runnable{
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        int i = 1;
    
        @Override
        public void run() {
            try {
                lock.lock();
                while (true) {
                    condition.signal();
                    if (i <= 100) {
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                        i++;
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } finally {
                lock.unlock();
            }
        }
    
    
        public static void main(String[] args) {
            ConditionTest test = new ConditionTest();
            Thread t1 = new Thread(test);
            Thread t2 = new Thread(test);
    
            t1.start();
            t2.start();
        }
    }
    

    拓展:

    启动三个线程, 一个输出 1,4,7,10…100, 一个输出 2,5,8,11…101,最后一个暑促3,6,9,12...102 最后 STDOUT 中按序输出 1,2,3,4,5…102

    实现:

    public class NotifyTest2 implements Runnable {
        private Object prev;
        private Object self;
        AtomicInteger i;
    
        private NotifyTest2(AtomicInteger num,Object prev, Object self) {
            this.i = num;
            this.prev = prev;
            this.self = self;
        }
    
    
        @Override
        public void run() {
            while (true) {
                synchronized (prev) {
                    synchronized (self) {
                        if (i.get() <= 102) {
                            System.out.println(Thread.currentThread().getName() + ":" + i.get());
                            i.getAndIncrement();
                            self.notify();
                        }
                    }
                    try {
                        prev.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static void main(String[] args)  {
            Object a = new Object();
            Object b = new Object();
            Object c = new Object();
            AtomicInteger num = new AtomicInteger(1);
            NotifyTest2 testA = new NotifyTest2(num,c,a);
            NotifyTest2 testB = new NotifyTest2(num,a,b);
            NotifyTest2 testC = new NotifyTest2(num,b,c);
    
            new Thread(testA).start();
            new Thread(testB).start();
            new Thread(testC).start();
        }
    }
    

    利用AtomicInteger做为共享变量。

  • 相关阅读:
    Struts2结合Ajax实现登录
    Java读取Properties文件
    职责链模式
    javaScript初学者易错点
    2019 DevOps 必备面试题——DevOps 理念篇
    如何成为一名优秀的敏捷团队负责人
    为什么企业敏捷团队会失败
    伪装的敏捷,我好累
    CODING 告诉你如何建立一个 Scrum 团队
    十倍程序员的传说
  • 原文地址:https://www.cnblogs.com/MarsCheng/p/10355945.html
Copyright © 2020-2023  润新知