博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
谈谈JDK线程的伪唤醒
阅读量:6268 次
发布时间:2019-06-22

本文共 4234 字,大约阅读时间需要 14 分钟。

  在JDK的官方的wait()方法的注释中明确表示线程可能被“虚假唤醒“,JDK也明确推荐使用while来判断状态信息。那么这种情况的发生的可能性有多大呢?

  使用生产者消费者模型来说明,伪唤醒造成的后果是本来未被唤醒的线程被唤醒了,那么就破坏了生产者消费者中的判断条件,也就是例子中的while条件number == 0或者number == 1。最终导致的结果就死0和1不能交替出现。

  JDK的两种同步方案均可能出现这种伪唤醒的问题(API说明明确表示会出现这种现象),这两种组合是synchronized+wait+notify和ReentrantLock+await+signal。下面的例子中,如果把while换成if,那么就0、1就不能交替出现,反制则会,例子中是100个线程进行增加,100个线程进行减少。

  在Java并发编程书上面引用了Thinking In Java的一句话说,大概意思是:任何并发编程都是通过加锁来解决。其实JDK并发编程也是通过加锁解决,每个对象都有一个对象锁,并且有一个与这个锁相关的队列,来实现并发编程。区别在于加锁的粒度问题,读读可以并发(在读远大于写的场景下比较合适),其他三种情况不能并发。而关系型数据库也是利用这一思想,只不过做得更加彻底,除了写写不能并发,其他三种情况都能并发,这得益于MVCC模型。

public class Resource {    public int number = 0;    public synchronized void add() {        while (number == 1) {            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        number++;        System.err.println(number + "-" + Thread.currentThread().getId());        notifyAll();    }    public synchronized void minus() {        while (number == 0) {            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        number--;        System.err.println(number + "-" + Thread.currentThread().getId());        notifyAll();    }    public static class AddThread implements Runnable {        private Resource resource;        public AddThread(Resource resource) {            this.resource = resource;        }        @Override        public void run() {            for (;;) resource.add();        }    }    public static class MinusThread implements Runnable {        private Resource resource;        public MinusThread(Resource resource) {            this.resource = resource;        }        @Override        public void run() {            for (;;) resource.minus();        }    }    public static void main(String[] args) {        Resource resource = new Resource();        for (int i = 0; i < 100; i++) {            new Thread(new AddThread(resource)).start();            new Thread(new MinusThread(resource)).start();        }    }}
public class ResourceLock {    private int number = 0;    private final ReentrantLock lock = new ReentrantLock();    private final Condition condition = lock.newCondition();    public int getNumber() {        return this.number;    }    public void increase() {        lock.lock();        try {            while (number == 1) {                condition.await();            }            number++;            System.err.println(number + "-" + Thread.currentThread().getId());            condition.signalAll();        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            if (lock.isHeldByCurrentThread()) {                lock.unlock();            }        }    }    public void decrease() {        lock.lock();        try {            while (number == 0) {                condition.await();            }            number--;            System.err.println(number + "-" + Thread.currentThread().getId());            condition.signalAll();        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            if (lock.isHeldByCurrentThread()) {                lock.unlock();            }        }    }    static class IncreaseThread implements Runnable {        private ResourceLock resource;        public IncreaseThread(ResourceLock resource) {            this.resource = resource;        }        @Override        public void run() {            for (;;) resource.increase();        }    }    static class DecreaseThread implements Runnable {        private ResourceLock resource;        public DecreaseThread(ResourceLock resource) {            this.resource = resource;        }        @Override        public void run() {            for (;;) resource.decrease();        }    }    public static void main(String[] args) throws Exception {        ResourceLock resource = new ResourceLock();        ExecutorService es = Executors.newFixedThreadPool(5);        for (int i = 0; i < 100; i++) {            es.submit(new IncreaseThread(resource));            es.submit(new DecreaseThread(resource));        }    }}

 

转载于:https://www.cnblogs.com/dreamroute/p/5936828.html

你可能感兴趣的文章
服务器端开发技术
查看>>
Python3中urllib详细使用方法(header,代理,超时,认证,异常处理)
查看>>
ajax提交多个对象,使用序列化表单和FormData
查看>>
深入分析由前序和中序重构二叉树问题
查看>>
leetcode 题解 || Valid Parentheses 问题
查看>>
将图片转成base64字符串并在JSP页面显示的Java代码
查看>>
什么是WeakHashMap--转
查看>>
js 面试题
查看>>
第二十二节,三元运算
查看>>
Yacc 与 Lex 快速入门
查看>>
Unity中HDR外发光的使用
查看>>
Flume负载均衡配置
查看>>
Ajax详解
查看>>
Ubuntu C/C++开发环境的安装和配置
查看>>
百世汇通快递地区选择插件,单独剥离
查看>>
Linux系统调用---同步IO: sync、fsync与fdatasync【转】
查看>>
【MyBatis学习06】输入映射和输出映射
查看>>
[LeetCode] Decode String 解码字符串
查看>>
数字逻辑的一些基本运算和概念
查看>>
ant重新编译打包hadoop-core-1.2.1.jar时遇到的错
查看>>