wait-notify模型面試題

一道面試題:面試

啓動兩個線程, 一個輸出 1,3,5,7…99, 另外一個輸出 2,4,6,8…100 最後 STDOUT 中按序輸出 1,2,3,4,5…100ide

錯誤實現1:this

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所表示的含義不一樣,咱們兩個線程裏面加上以下代碼code

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

會發現打印出對象

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

原來兩個this不是同一個對象,匿名類會生成新的對象,因此致使兩個線程獲取的monitor鎖是不一樣的。這就致使wait()方法調用以後,兩個線程都被掛起,可是再也沒人能把他們喚醒,並且因爲鎖不一樣,兩個線程都同時執行了,打印出的都是1。rem

正確實現:get

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實現:it

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();
    }
}

拓展:io

啓動三個線程, 一個輸出 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作爲共享變量。

相關文章
相關標籤/搜索