3_线程间通信

Posted root_zhb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3_线程间通信相关的知识,希望对你有一定的参考价值。


场景:有多个线程,实现对一个初始值为0的变量进行操作,实现如下效果(不要求ABCD的顺序)
A 1   B 0  C 1  D 0
A 1   B 0  C 1  D 0
A 1   B 0  C 1  D 0

1、虚假唤醒问题

1.1、错误代码

//第一步:创建资源类,定义属性和操作方法
class Share{
    //初始值
    private int number=0;
    // +1的方法
    public synchronized void incr() throws InterruptedException {
        //第二步:判断、干活、通知
        if(number!=0){  //判断number的值是否是0,如果不是0,等待
            this.wait();
        }
        //如果number值是0,就+1操作
        number++;
        System.out.println(Thread.currentThread().getName()+"::"+number);
        //通知其他线程
        this.notifyAll();
    }
    // -1的方法
    public synchronized void decr() throws InterruptedException {
        //判断
        if(number!=1){  //判断number的值是否是1,如果不是1,等待
            this.wait();
        }
        //干活
        number--;
        System.out.println(Thread.currentThread().getName()+"::"+number);
        //通知其他线程
        this.notifyAll();
    }

}
public class ThreadTest {
    public static void main(String[] args) {
        Share share=new Share();

        new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"AA").start();

        new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"BB").start();

        new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    share.incr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"CC").start();

        new Thread(()->{
            for (int i=0;i<10;i++){
                try {
                    share.decr();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"DD").start();
    }
}

1.2、现象

BB::4
DD::3
BB::2
CC::3
AA::4
CC::5

1.3、原因分析


简单来说,就是当某个线程第二次醒来之后,没有进行判断

1.4、解决

不管什么时候,让线程醒来之后,再次判断即可,也就是 wait()方法总是应该在循环中使用。

//将两个判断方法改成while循环
while(number!=0){  
    this.wait();
}
while(number!=1){  
    this.wait();
}

2、Synchronized 实现

将两个判断条件替换为while循环,即为synchronized实现。

3、Lock实现

//第一步:创建资源类,定义属性和操作方法
class Share{
    //初始值
    private int number=0;
    //创建Lock
    private Lock lock=new ReentrantLock ();
    private Condition condition=lock.newCondition();

    // +1的方法
    public void incr() throws InterruptedException {
        //上锁
        lock.lock();
        try {
            //判断、干活、通知
            while(number!=0){
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"::"+number);
            condition.signalAll();
        }finally {
            //解锁
            lock.unlock();
        }
    }
    // -1的方法
    public  void decr() throws InterruptedException {
        lock.lock();
        try {
            while(number!=1){
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"::"+number);
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }
}

以上是关于3_线程间通信的主要内容,如果未能解决你的问题,请参考以下文章

线程__线程间的通信

多线程_线程间通信

阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第4节 等待唤醒机制_5_线程间通信

线程_进程间通信Queue合集

线程_进程间通信Queue合集

Python简单线程间通信