龙空技术网

Java线程中虚假唤醒问题

Java老油条 145

前言:

现在兄弟们对“java线程的唤醒”大约比较重视,小伙伴们都想要知道一些“java线程的唤醒”的相关文章。那么小编在网上网罗了一些关于“java线程的唤醒””的相关知识,希望咱们能喜欢,朋友们一起来了解一下吧!

先定义资源类 :包含资源数量,消费方法,生产方法

当资源为0时,生产者生产资源

当资源为1时,消费者消费资源

//定义Resource作为线程需要的资源public class Resource {    //当前资源的数量    int num=0;    //当前资源的上限    int size=1;    //消费资源    public synchronized void remove(){        if(num==0){            try {                System.out.println("消费者等待");                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        num--;        System.out.println("消费者线程为:"+Thread.currentThread().getName()+"资源数量"+num);        notifyAll();    }    //生产资源    public synchronized void put(){        if(num==size){            try {                System.out.println("生产者等待");                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        num++;        System.out.println("生产者线程为:"+Thread.currentThread().getName()+"资源数量"+num);        notifyAll();    }}复制代码

创建消费者线程

//定义Consumer使用remove消费资源public class Consumer implements Runnable {    private Resource resource;    public Consumer(Resource resource) {        this.resource = resource;    }    @Override    public void run() {        for(int i=0;i<10;i++){            resource.remove();        }    }}复制代码

创建生产者线程

//定义Producer使用put生产资源public class Producer implements Runnable {    private Resource resource;    public Producer(Resource resource) {        this.resource = resource;    }    @Override    public void run() {        for(int i=0;i<10;i++){            resource.put();        }    }}复制代码

执行线程

public static void main(String[] args) {    Resource resource = new Resource();    Consumer consumer = new Consumer(resource);    Producer producer = new Producer(resource);    new Thread(consumer).start();    new Thread(producer).start();}复制代码

可以发现:线程执行情况正常

但是当我们分别有两个消费者和生产者时,线程执行就出现了异常

public static void main(String[] args) {    Resource resource = new Resource();    Consumer consumer = new Consumer(resource);    Producer producer = new Producer(resource);    new Thread(producer,"生产者1").start();    new Thread(producer,"生产者2").start();    new Thread(consumer,"消费者1").start();    new Thread(consumer,"消费者2").start();}复制代码

这就是虚假唤醒问题

当我们的线程执行了start,此时线程都进入就绪状态

生产者1获取cpu执行权,变为运行状态,执行其中run方法,资源数+1

接着生产者1和生产者2先后获取cpu执行权,因为资源数为1,线程阻塞

消费者获取cpu执行权,资源数-1,并且会唤醒阻塞的线程

这时候就变成最初的状态

当生产者再次执行,是从刚才阻塞的地方继续运行,就不用再判断资源的数量是否为0了

出现虚假唤醒的原因是从阻塞态到就绪态再到运行态没有进行判断

我们可以每次得到操作权时都进行判断,将if判断改成while判断即可

此时执行情况正常

作者:十二时辰_

链接:

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签: #java线程的唤醒