java 线程基础之使用while循环代替if条件防止虚假唤醒

先来看看下面的程序

A、C两个线程做number的增1,B、D 两个线程做number的减1

class MpCust {

    private int number = 0;
    public synchronized void increment() throws InterruptedException {
        if (number != 0){
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"\n"+number);
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        if (number==0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"\n"+number);
        this.notifyAll();
    }

    public static void main(String[] args) {
        MpCust mpCust = new MpCust();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(300);
                        mpCust.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"A").start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(400);
                        mpCust.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"B").start();




        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(300);
                        mpCust.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"C").start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(400);
                        mpCust.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"D").start();


    }

}

运行结果中有值打印为2,这是不正常的!


image.png

因为increment()方法执行到这里,number 的值不为0的话就会执行Object.wait()方法,当前线程会进入等待。

    if (number != 0){
            this.wait();
    }

因为这段代码是在多线程下执行的,线程执行到 this.wait();等待,苏醒后继续执行。这时候如果别的线程已经将number的值改为1,那么就不会再去判断一次number 是否等于0,就直接往下执行number++,导致number的值为2。这种想象我们称之为虚假唤醒

所以需要一种机制让线程苏醒之后再次判断number的值是否等于0。这时候java中的while循环正好排上用场。

使用while循环代替if条件
    while(number != 0){
            this.wait();
    }
class MpCust {

    private int number = 0;
    public synchronized void increment() throws InterruptedException {
        while (number != 0){
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"\n"+number);
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        while (number==0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"\n"+number);
        this.notifyAll();
    }

    public static void main(String[] args) {
        MpCust mpCust = new MpCust();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(300);
                        mpCust.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"A").start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(400);
                        mpCust.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"B").start();




        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(300);
                        mpCust.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"C").start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(400);
                        mpCust.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }

            }
        },"D").start();


    }

}

完美~~


image.png
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容