Java多线程操作同一份资源

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

package com.yangyuanyuan.juc1205;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Aircondition
{
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void increment()throws Exception
    {
        lock.lock();
        try
        {
            //1 判断
            while (number != 0)
            {
                condition.await();//this.wait();
            }
            //2 干活
            number++;
            System.out.println(Thread.currentThread().getName()+"\t"+number);
            //3 通知
            condition.signalAll();//this.notifyAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void decrement()throws Exception
    {
        lock.lock();
        try
        {
            //1 判断
            while (number == 0)
            {
                condition.await();//this.wait();
            }
            //2 干活
            number--;
            System.out.println(Thread.currentThread().getName()+"\t"+number);
            //3 通知
            condition.signalAll();//this.notifyAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    /*public synchronized void increment()throws Exception
    {
        //1 判断
        while (number != 0)
        {
            //AAA  CCC
            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();
    }*/

}

/**
    1    高聚低合前提下,线程操作资源类
    2   判断/干活/通知
    3   防止虚假唤醒 不能使用if判断,会出现2

   知识小总结 = 多线程编程套路+while判断+新版写法
 */
public class ProdConsumerDemo04
{
    public static void main(String[] args)throws  Exception
    {
        Aircondition aircondition = new Aircondition();

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

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

    }
}

使用if判断存在虚假唤醒情况,变量可能会变成2

如图所示,如果只有两个线程,一个线程加,一个线程减,不会存在虚假唤醒情况(选无可选)。

当变成四个线程时,两个线程加,两个线程减,使用if就会存在虚假唤醒情况。如变量初始为0(0!=0为false),执行完+’变量变成1,此时+线程进来发现值为1等待(this.wait()处等待,未出if判断),然后+‘线程又进来发现值为1它也等待(this.wait()处等待,未出if判断),此时-线程进来(1==0为false)发现变量值为1将变量做减法变成0。由于此时+和+‘仍在等待,cpu为了降低消耗量和负担,会先满足等待时间长的线程(线程优先级会高)

由于使用的是if,不会再拉回来重新判断一次(两个线程this.wait()处等待),+和+’线程都会做加法,变量值就变成了2。

posted @ 2021-01-24 10:49  勤奋的园  阅读(623)  评论(0编辑  收藏  举报