JUC之线程通知

上一次说道,线程操作记住:线程  操作  资源类,高内聚低耦合,这是上

下(wait和notify)口诀: 判断/干活/通知   ,虚假唤醒

一、案例 1(两个线程)

 现在两个线程,可以操作初始值为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替,来10轮。

资源类:可以结合判断 干活  通知,注意是if判断只判断一次,后面会讲到

class ShareData
{
    private int number = 0;

    public synchronized void increment()throws Exception
    {
        //1 判断
        if(number != 0)
        {
            this.wait();
        }
        //2 干活
        ++number;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //3 通知
        this.notifyAll();
    }

    public synchronized void decrement()throws Exception
    {
        //1 判断
        if(number == 0)
        {
            this.wait();
        }
        //2 干活
        --number;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //3 通知
        this.notifyAll();
    }
}

测试类:

public class ProdConsumerDemo
{
    public static void main(String[] args)
    {
        ShareData sd = new ShareData();

        new Thread(() -> {
            for (int i = 1; i <=10; i++)
            {
                try {
                    sd.increment();
                    Thread.sleep(200);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(() -> {
            for (int i = 1; i <=10; i++)
            {
                try {
                    sd.decrement();
                    Thread.sleep(300);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"B").start();

    }
}

二、案例 2(多个线程)解决虚假唤醒

如果说将上面的改成两个生产者,两个消费者,而其他的不变则出现线程不安全问题了,  为什么呢?

分析: 例如,当一个生产者生产了一个当抢占到cpu会处于wait等待阶段,此时万一另一个生产者抢占了cpu资源,发现已经生成了一个,也处于等待,此时另外两个消费者任意一个可以抢占cpu,进行消费,然后消费完后,资源为0唤醒生产者,此时,一个生产者会唤醒,进行下一步的生成生产结束,而另一个生产者也将有可能在次进行生产,重要的是,用if已经判断过一次了,不用在判断,所以会在生产出两个,与生产一个消费一个不符,所以 解决措施就是使其多次判断,即使用while代替if。

而JDK官方文档也指出,最好使用while代替if

  • As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
    •     synchronized (obj) {
               while (<condition does not hold>)
                   obj.wait();
               ... // Perform action appropriate to condition
           }
      

 

所以本段代码是:

资源段:注意while

class ShareData
{
    private int number = 0;

    public synchronized void increment()throws Exception
    {
        //1 判断
        while(number != 0)
        {
            this.wait();
        }
        //2 干活
        ++number;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //3 通知
        this.notifyAll();
    }

    public synchronized void decrement()throws Exception
    {
        //1 判断
        while(number == 0)
        {
            this.wait();
        }
        //2 干活
        --number;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //3 通知
        this.notifyAll();
    }
}

测试:

public class ProdConsumerDemo
{
    public static void main(String[] args)
    {
        ShareData sd = new ShareData();

        new Thread(() -> {
            for (int i = 1; i <=10; i++)
            {
                try {
                    sd.increment();
                    Thread.sleep(200);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(() -> {
            for (int i = 1; i <=10; i++)
            {
                try {
                    sd.decrement();
                    Thread.sleep(300);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"B").start();

        new Thread(() -> {
            for (int i = 1; i <=10; i++)
            {
                try {
                    sd.increment();
                    Thread.sleep(300);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

        new Thread(() -> {
            for (int i = 1; i <=10; i++)
            {
                try {
                    sd.decrement();
                    Thread.sleep(400);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}

 

 

 

 

 

 

 

    原文作者:JUC
    原文地址: https://blog.csdn.net/student__software/article/details/81914202
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞