Java并发编程实战 第14章 构建自定义的同步工具
状态依赖性
定义:只有满足特定的状态才能继续执行某些操作(这些操作依赖于固定的状态,这些状态需要等待别的线程来满足)。
FutureTask,Semaphroe,BlockingQueue等,都是状态依赖性的类。
条件队列
条件对列:条件对列就是由于不满足继续的条件而被wait操作阻塞的线程队列。他们都在等待条件满足,然后被唤醒。
条件谓词:状态依赖性依赖的前提条件。如BlockingQueue中的isFull,isEmpty等。
条件等待中存在三个要素:加锁 + 条件谓词 + wait方法
wait方法和notify方法
我理解的wait方法:会释放锁+阻塞当前线程,放入条件对列,等待被唤醒,唤醒后,需要重新获得锁,获得锁之后继续执行wait那句代码所在的位置(即使wait在锁块的中间代码部分)。
notify(All)方法:只是唤醒条件队列中的线程。但是不释放锁。
使用wait notify方法的时候,一定要持有条件对列所属的锁。
使用轮询和休眠实现简单的状态依赖性阻塞
- while(true)
- {
- //这里不对循环上锁,不然这个锁就无法释放了,不对休眠上锁,休眠上锁,在休眠的时候别人也无法操作,永远都不可能有元素出去
- synchronized (this)
- {
- //如果队列不是满的,那么就放入元素
- if(!this.isFull())
- {
- this.doPut(v);
- return;
- }
- }
- //否则休眠,退出cpu占用
- Thread.sleep(SLEEP_GRANULARITY);
- }
- }
使用条件队列来实现状态依赖性阻塞
- public synchronized void put(V v) throws InterruptedException
- {
- while(this.isFull())
- {
- //这里挂起程序,会释放锁
- this.wait();
- }
- //如果队列不为满的,那么程序被唤醒之后从新获取锁
- this.doPut(v);
- //执行结束,唤醒其他队列
- this.notifyAll();
- }
注意上面要使用while。
对于监视器来说,wait操作产生的线程,都放在这个监视器唯一的条件队列里。
如果使用Lock,可以使用condition来产生不同的条件对列。
注意上面的 this.notifyAll();代码,将会唤醒这个监视器条件队列里所有等待的线程。其实这里只用唤醒因为empty阻塞的线程,而不用唤醒因为full阻塞的线程。
如果使用 this.notify(),只会随机唤醒一个,如果唤醒的是因为full堵塞的线程,那么就可能没有正常唤醒。影响性能,甚至造成活跃性的危险。
这种情况下,可以使用Lock和Condition来改造。
- protected final Lock lock = new ReentrantLock();
- private final Condition notFull = lock.newCondition();
- private final Condition notEmpty = lock.newCondition();
- public void put(T x) throws InterruptedException {
- lock.lock();
- try {
- while (count == items.length)
- notFull.await();
- items[tail] = x;
- if (++tail == items.length)
- tail = 0;
- ++count;
- notEmpty.signal();
- } finally {
- lock.unlock();
- }
- }
注意:这里不是signalAll。
阀门类
使用闭锁CountDownLatch,传入1的时候可以作为阀门开关。前提是在其他线程的第一步先执行开关的await。使用开关的countDown方法就可以打开开关。
但是这种阀门,只能打开,不能关闭。
使用wait和notifyAll来实现可重新关闭的阀门。
Condition
注意,由于Condition对象继承自Object,它也有wait,notify,notifyAll方法,其实它对应方法名字应该是await,signal,signalAll。
最新文章
- discuz sphinx全文检索搜索引擎方案
- 使用if else if else 统计计算
- jQuery源代码学习之七—队列模块queue
- 张小龙《微信背后的产品观》之PPT完整文字版
- auto_ptr的使用原则
- 10 Code Coverage Tools for C &; C++
- ASP.NET几种清除页面缓存的方法
- zabbix 布署实践【6 使用微信公众号-消息模版推送告警】
- jQuery软键盘插件
- JS实现AOP拦截方法调用
- 3D Slicer中文教程(四)—图像分割
- babel (二) update to v7
- 总结mysql的三种外键约束方式
- 微信H5开发
- javascript 函数对象
- jQuery学习- 内容选择器
- PHP unlink()函数,删除文件
- 响应式Web设计-一种优雅的掌上展现
- C++学习笔记——C++简介
- 为什么要实现Serializable