博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
wait & notify & notifyAll_实现有界缓存
阅读量:5765 次
发布时间:2019-06-18

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

hot3.png

wait & notify & notifyAll_实现有界缓存

接上篇:

条件队列就好像面包机中通知”面包以烤好“的铃声。如果你注意听着铃声,那么当前面包烤好后可以立刻得到通知,然后放下手头的事情(或者先把手头的事情做完,例如先看完报纸)开始品尝面包。如果没有听见铃声(可能出去拿报纸了),那么就会错过通知信息,但回到厨房时,还可以观察烤面包机的状态,如果已经烤好,那么就会取出面包,如果还未烤好,就再次留意铃声。

条件队列这个名字来源于:它使得一组线程(称之为等待线程集合)能够通过某种方式来等待特定的条件变为真。

每个Java对象都可以作为一个锁,每个对象同样可以作为一个条件队列,并且Object中的wait,notify和notifyAll方法就构成了内部条件队列的API。对象的内置锁与其内部条件队列是相互关联的,要调用对象X中条件队列的任何一个方法,必须持有对象X上的锁。只有能对状态检查时,才能在某个条件上等待,并且只有修改状态时,才能从条件等待中释放另一个线程。

Object.wait()会自动释放锁,并请求操作系统挂起当前线程,从而使其他线程能够获得这个锁并修改对象的状态。

先来了解一下Object.wait和notify方法,见文章:

 

使用条件队列实现的有界缓存

在下面这段程序中实现了基于wait和notifyAll的一个有界缓存。这比使用了休眠的有界缓存更简单,更高效(当缓存状态没有发生改变时,线程醒来的次数将更少),响应性也更高(当发生特定状态变化时将立即醒来)。这是一个较大的改进,但是要注意:与使用休眠的有界缓存相比,条件队列并没有改变原来的语义。它只是在多个方面进行了优化:CPU效率、上下文切换开销和响应性等。如果某个功能无法通过”轮询和休眠“来实现,那么使用条件队列也无法实现,但条件队列在使得在表达和管理状态依赖性时更加简单和高效。

看程序实现:

package sync;/** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-9-1 * Time: 下午5:17 * To change this template use File | Settings | File Templates. */public class BoundBuffer
 extends BaseBoundedBuffer
 {    protected BoundBuffer(int capacity) {        super(capacity);    }    // 阻塞并直到:NOT FULL    public synchronized void put(V v) throws InterruptedException {        while (isFull()) {            System.out.println("put wait");            // 释放当前线程持有的内置锁,并请求操作系统挂起当前线程,            // 直到其他线程调用notifyAll解除该线程的阻塞状态,并重新获得内置锁。            wait(); //调用wait意味着我要休息了        }        doPut(v);        //调用通知方法意味着铃响,也就是发生了特定的事情唤醒阻塞的线程。        notifyAll(); //解除所有那些在该对象上调用wait方法的线程的阻塞状态。    }    public synchronized V take() throws InterruptedException {        while (isEmpty()) {            System.out.println("take wait");            wait();        }        V v = doTake();        notifyAll();        return v;    }    public static void main(String args[]) {        final BoundBuffer buffer = new BoundBuffer(10);        //线程t2打印缓存中的消息        Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        System.out.println(buffer.take());                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        //线程t1放入缓存消息        Thread t1 = new Thread(new Runnable() {            @Override            public void run() {                for (int i = 0; i < 100; i++) {                    try {                        buffer.put(new String("sadsasd"));                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        //只有两个线程组成的等待条件为真的线程集合        t2.start();        t1.start();    }}

后记:Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

==============END==============

转载于:https://my.oschina.net/xinxingegeya/blog/308835

你可能感兴趣的文章
Ubuntu - unixodbc 配置 - zhouzhk - ITeye技术网站
查看>>
C#循环语句-先判断后执行-while循环
查看>>
.net便利的小方法
查看>>
SQL Server计算数据库中表、堆、聚集索引和非聚集索引的大小
查看>>
VS创建Web项目的两种形式WebSite和WebApplicationd的区别!
查看>>
查看SQLSERVER内部数据页面的小插件Internals Viewer
查看>>
文件拷贝
查看>>
MySQL Workbench的使用教程 (初级入门版)
查看>>
python实现mapreduce(2)——在hadoop中执行
查看>>
c++ 重载 >>(输入) 、<< (输出) 操作符
查看>>
经验分享:CSS浮动(float,clear)通俗讲解
查看>>
懒得说IE6了,写个js插件不能写注释,原因如下
查看>>
Kendo UI开发教程(25): 单页面应用(三) View
查看>>
python查找算法的实现-二分法
查看>>
如何提高Lucene构建索引的速度
查看>>
ping 原理与ICMP协议---转
查看>>
svn导出文件进行比较
查看>>
如何将内存中的位图数据绘制在DC上
查看>>
Angular学习(4)- 数组双向梆定
查看>>
Shell下的通配符、特殊符号和文件描写叙述符
查看>>