最近在看pthread方面的书,看到条件变量一节的时候,回忆了下java中条件变量的使用方式。

java中条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
 
条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细。
通熟易懂的说,就是消费者/生产者的场景中,在原来的基础上,增加了队列满时及时通知消费者,队列空时及时通知生产者的优化,通常是两个条件变量一起出现,一个控制值,但两个条件变量可以毫无关系,终归来说还是在Lock的范围内。所以,从本质上来说,是对Object监视器的场景性优化,而不是全新机制的引入。
 
从现实应用角度来说,它们常被用于下列场景:
1、写log。比如每1秒或者commit或者日志大于1/3m时候都写入。缓存中大于1/3m时需要等写入完成才能commit。
 
而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。有关Condition接口详细说明可以具体参考JavaAPI文档。

如下:public class TestConditon

public static void main(String[] args) {
// 创建并发访问的账户
MyCount myCount = new MyCount("95599200901215522", 10000);
// 创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(3); #假设改成2会怎么样??
Thread t1 = new SaveThread("张三", myCount, 1000);
Thread t2 = new SaveThread("李四", myCount, 1000);
Thread t3 = new DrawThread("王五", myCount, 12600);
Thread t4 = new SaveThread("老张", myCount, 600);
Thread t5 = new DrawThread("老牛", myCount, 1300);
Thread t6 = new DrawThread("胖子", myCount, 800);
Thread t7 = new SaveThread("测试", myCount, 2100);
// 执行各个线程
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
// 关闭线程池
pool.shutdown();
}
} /**
* 存款线程类
*/
class SaveThread extends Thread {
private String name; // 操作人
private MyCount myCount; // 账户
private int x; // 存款金额 SaveThread(String name, MyCount myCount, int x) {
this.name = name;
this.myCount = myCount;
this.x = x;
} public void run() {
myCount.saving(x, name);
}
} /**
* 取款线程类
*/
class DrawThread extends Thread {
private String name; // 操作人
private MyCount myCount; // 账户
private int x; // 存款金额 DrawThread(String name, MyCount myCount, int x) {
this.name = name;
this.myCount = myCount;
this.x = x;
} public void run() {
myCount.drawing(x, name);
}
} /**
* 普通银行账户,不可透支
*/
class MyCount {
private String oid; // 账号
private int cash; // 账户余额
private Lock lock = new ReentrantLock(); // 账户锁
private Condition _save = lock.newCondition(); // 存款条件
private Condition _draw = lock.newCondition(); // 取款条件 MyCount(String oid, int cash) {
this.oid = oid;
this.cash = cash;
} /**
* 存款
*
* @param x
* 操作金额
* @param name
* 操作人
*/
public void saving(int x, String name) {
lock.lock(); // 获取锁
if (x > 0) {
cash += x; // 存款
System.out.println(name + "存款" + x + ",当前余额为" + cash);
}
_draw.signalAll(); // 唤醒所有等待线程。
lock.unlock(); // 释放锁
} /**
* 取款
*
* @param x
* 操作金额
* @param name
* 操作人
*/
public void drawing(int x, String name) {
lock.lock(); // 获取锁
try {
while (cash - x < 0) {
_draw.await(); // 阻塞取款操作, await之后就隐示自动释放了lock,直到被唤醒自动获取
System.out.println(name + "阻塞中");
}
{
cash -= x; // 取款
System.out.println(name + "取款" + x + ",当前余额为" + cash);
}
_save.signalAll(); // 唤醒所有存款操作
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
}
}

需要注意的是,在共用一个线程池的设计中,特别要注意饿死现象(就像上下高速如果公用车道的话,万一进入的10车全部占坑了,高速里面又满了的话,想出的都出不来,进的进不去,就出现饿死现象了),如果有大量的消费者使得生产者线程无法再运行的话,就会出现该问题,在上述例子中,将线程池数量从3改成2就可以多次测试中发现程序hang了。

所以,我们可以看到典型的在RDBMS系统中都是各种线程各司其职。

详细接口用法可参考javadoc如下:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

java Condition条件变量的通俗易懂解释、基本使用及注意点的更多相关文章

  1. Condition条件变量

    条件变量是一种比较复杂的线程同步机制 #!/usr/bin/env python # -*- coding: utf-8 -*- """ 条件变量,线程间通信提供的另一种 ...

  2. Java 23种设计模式 (通俗易懂解释收集整理)

    (补充中...) P02 抽象工程模式 P14 TemplateMethod 模板方法模式 讲清楚了为什么叫做模板方法  http://www.cnblogs.com/java-my-life/arc ...

  3. 深入浅出 Java Concurrency (9): 锁机制 part 4 锁释放与条件变量 (Lock.unlock And Condition)

    本小节介绍锁释放Lock.unlock(). Release/TryRelease unlock操作实际上就调用了AQS的release操作,释放持有的锁. public final boolean ...

  4. (转)Java线程:新特征-条件变量

    Java线程:新特征-条件变量   条件变量是Java5线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量.但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往 ...

  5. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  6. 27 python 初学(信号量、条件变量、同步条件、队列)

    参考博客: www.cnblogs.com/yuanchenqi/articles/5733873.html  semaphore 信号量: condition 条件变量: event 同步条件:条件 ...

  7. [development][C] 条件变量(condition variables)的应用场景是什么

    产生这个问题的起因是这样的: ‎[:] ‎<‎tong‎>‎ lilydjwg: 主线程要启动N个子线程, 一个局部变量作为把同样的参数传入每一个子线程. 子线程在开始的十行会处理完参数. ...

  8. Java线程:条件变量、原子量、线程池等

    一.条件变量 条件变量实现了java.util.concurrent.locks.Condition接口,条件变量的实例化就是通过一个Lock对象上调用newCondition()方法获得的,这样条件 ...

  9. 转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)

    简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接 ...

随机推荐

  1. [Java in NetBeans] Lesson 17. File Input/Output.

    这个课程的参考视频和图片来自youtube. 主要学到的知识点有: We want to handle the bad Error. (e.g bad input / bugs in program) ...

  2. Python字典和集合的内部实现

    1. 哈希表(Hash tables) 在Python中,字典是通过哈希表实现的.也就是说,字典是一个数组,而数组的索引是经过哈希函数处理后得到的.哈希函数的目的是使键均匀地分布在数组中.由于不同的键 ...

  3. gitlab4.0备份还原

    一,备份 备份默认路径查看: gitlab/config/gitlab.yml 中的backup: 默认tmp/backups ====>这个是gitlab/tmp/backups/  可不是系 ...

  4. RSA加解密 私钥加密公钥解密 私加公解 && C++ 调用openssl库 的代码实例

    前提:秘钥长度=1024 ============================================== 对一片(117字节)明文加密  私加 ===================== ...

  5. LeetCode155.最小栈

    设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈. push(x) -- 将元素 x 推入栈中. pop() -- 删除栈顶的元素. top() -- 获取栈顶元素. ...

  6. List<String> 2List <Long>

    public static List<Integer> CollStringToIntegerLst(List<String> inList){ List<Integer ...

  7. ef entity转json引起的Self referencing loop

    问题简介:前段时间做项目时,将取到的entity往Redis cache里存放时报多重引用的错误. Self referencing loop detected for property 'Check ...

  8. shader之法线变换

    对于法线变换,进行非统一缩放时,如果使用跟变换顶点相同的变换矩阵来变换法线,则会得到错误的结果,即变换后的法线方向与平面不再垂直. 如何求得变换法线的矩阵呢: 转载请注明出处:http://www.c ...

  9. django user 权限

     Django中的Users权限系统 2011-05-21 15:04:33 分类: Python/Ruby 权限系统包含1.用户2.权限(判断一个用户是否有特定的操作权限yes/no)3.组4.消息 ...

  10. SQL 中的连接查询

    关于SQL的应用,肯定离不开查询,而相对复杂的查询,总是离不开对表的连接,单个表操作的并不罕见,但是在应用环境大多数的查询都是针对2.3个表甚至更多的表7,至于连接,有内连接.外链接.交叉连接之分,每 ...