【Java】并发之锁与条件
来源:互联网 发布:乍得内战知乎 编辑:程序博客网 时间:2024/06/08 08:07
讨论锁机制,少不了“生产者-消费者”这个经典场景。
多线程中,为什么需要锁?因为多个线程同时访问同一个资源,会出现同时修改的问题。所以,得加一把锁,A线程开始访问该资源时,锁上,此时,B线程就得等待于门外;当A线程访问完毕,解锁,即开门了,B线程才得以进入。
在Java中,可以定义一个Object类型的锁对象,通过synchronized关键词实现线程锁的作用。Java5开始,提供ReentrantLock这个类,锁上通过lock()方法,解锁通过unlock()方法,可取代synchronized用法。代码如下:
class Factory {private int count = 0;//存货数量private ReentrantLock lock = new ReentrantLock();/** * 生产1个产品 */public void produce() {lock.lock();try {System.out.println("生产1个,现有 : " + (++count));} finally {lock.unlock();}}/** * 卖出1个产品 */public void consume() {lock.lock();try {System.out.println("卖出1个,现有 : " + (--count));} finally {lock.unlock();}}}
构造1000个线程执行上例中的produce()方法和,1000个线程执行consume()方法,即模拟现实中生产1000个产品,卖出1000个产品,最终的结果,会剩下0个。因为我们加了同步锁控制。如果没有加锁的话,由于produce()方法和consume()方法同时竞争资源(本例中的“资源”为存货个数count),发生混乱,最终打印的结果很可能不是为0。通过打印的结果,我们发觉,打印存货个数时,可能为负数,这是与现实不符合的。因为,在consume()方法中可能没有产品可卖了,即现实中的产品供不应求的意思。但程序不解理啊,需要存货个数为0,但程序仍让它卖出,继续减1操作,就成了负数了。
为避免这种现象,就设立一个“有货可卖”的条件,满足这个条件,才允许卖出产品,否则,就得等待,直到生产方有生产出产品为止。
而现实中又有另一需要,工作不敢无限量地生产产品,担心卖不出去,所以,得控制存货的数量,例如:最多存货100个。
Java并发API中,使用了Condition类来实现线程之间的协作控制,我们修改上面的程序如下:
class Factory {private int count = 0; // 存货数量private ReentrantLock lock = new ReentrantLock();private Condition notEmptyCondition = lock.newCondition(); // “有货可卖”条件private Condition notFullCondition = lock.newCondition(); // “允许生产”条件/** * 生产1个产品 */public void produce() {lock.lock();try {while (count == 100) {// 封顶了,暂时不能继续生产,线程我阻塞中,等待卖出产品然后通知我继续生产产品(即继续执行下面的代码)notFullCondition.await();}++count; // 生产1个产品System.out.println("生产1个,共有 : " + count);// 新生产了1个产品,“有货可卖”条件加1,通知受困于notEmptyCondition.await()的线程可以销售1个产品了notEmptyCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}/** * 卖出1个产品 */public void consume() {lock.lock();try {while (count == 0) {// 库空了,暂时不能继续销售,线程我阻塞中,等待生产出产品然后通知我继续销售产品(即执行下面的代码)notEmptyCondition.await();}--count; // 卖出1个产品System.out.println("卖出1个,剩下 : " + count);// 新卖出了1个产品,“允许生产”条件加1,通知受困于notFullCondition.await()的线程可以生产1个产品了notFullCondition.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}
这样理解,Condition对象内有一记数器,每调用一次await()方法,就会记录有1个线程阻塞在这里,等待其他的线程调用1次signal()方法,以唤醒这个线程可以继续执行await()后面的代码了。
另外,区别一下signal()和signalAll()方法。signal()只能唤醒1个阻塞在await()处的线程;而signalAll()可唤醒所有阻塞在await()处的线程。
理解Java多线程的锁和条件的用法,对掌握并发集合类(如ConcurrentHashMap, ArrayBlockQueue等)有很大的好处。
@容新华技术博客 - http://blog.csdn.net/rongxinhua - 原创文章,转载请注明出处
0 0
- 【Java】并发之锁与条件
- java并发包:重入锁与Condition条件
- Java 8 并发之同步与锁
- JAVA并发-条件队列
- Java多线程与并发应用-(9)-锁lock+条件阻塞conditon实现线程同步通信
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)(r)
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
- Java并发编程之二十:并发新特性—Lock锁和条件变量(含代码)
- 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)
- java并发包学习系列:重入锁与Condition条件
- Java并发系列-6、竞态条件与临界区
- java并发-竞态条件与临界区(3)
- Java并发之读写锁Lock和条件阻塞Condition的应用
- Java并发之读写锁Lock和条件阻塞Condition的应用
- debian修改ssh端口
- NYOJ 254 编号统计
- getContentResolver()
- (转载)浅析error LNK2001: unresolved external symbol "public: __thisc...
- weblogic从属服务器启动
- 【Java】并发之锁与条件
- mapinfo教程
- 代码耦合
- python写的掉空格数字字母的方法
- 输入目录,清除目录下的class文件
- C++多态的灵活运用
- LeetCode 题解(13):Regular Expression Matching
- 0-1背包问题——小P寻宝记
- POJ 1423 Big Number