Java并发编程实践 目录

并发编程 01—— ThreadLocal

并发编程 02—— ConcurrentHashMap

并发编程 03—— 阻塞队列和生产者-消费者模式

并发编程 04—— 闭锁CountDownLatch 与 栅栏CyclicBarrier

并发编程 05—— Callable和Future

并发编程 06—— CompletionService : Executor 和 BlockingQueue

并发编程 07—— 任务取消

并发编程 08—— 任务取消 之 中断

并发编程 09—— 任务取消 之 停止基于线程的服务

并发编程 10—— 任务取消 之 关闭 ExecutorService

并发编程 11—— 任务取消 之 “毒丸”对象

并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性

并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略

并发编程 14—— 线程池 之 整体架构

并发编程 15—— 线程池 之 原理一

并发编程 16—— 线程池 之 原理二

并发编程 17—— Lock

并发编程 18—— 使用内置条件队列实现简单的有界缓存

并发编程 19—— 显式的Conditon 对象

并发编程 20—— AbstractQueuedSynchronizer 深入分析

并发编程 21—— 原子变量和非阻塞同步机制

概述

第1部分  定义

第2部分 实例

参考

第1 部分 定义

Condition 是一种广义的内置条件队列,接口如下:

public interface Condition {
// 造成当前线程在接到信号或被中断之前一直处于等待状态。
void await();
// 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
boolean await(long time, TimeUnit unit);
// 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
long awaitNanos(long nanosTimeout);
// 造成当前线程在接到信号之前一直处于等待状态。
void awaitUninterruptibly();
// 造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。
boolean awaitUntil(Date deadline);
void signal(); // 唤醒一个等待线程
void signalAll(); // 唤醒所有等待线程
}

  一个Condition和一个Lock关联在一起,就像一个条件队列和一个内置锁相关联一样。要创建一个Condition,可以在相关联的Lock上调用Lock.newCondition方法。正如Lock比内置加锁提供了更为丰富的功能,Condition同样比内置条件队列提供了更丰富的功能:在每个锁上可存在多个等待、条件等待可以是可中断的或不可中断的、基于时限的等待,以及公平的或非公平的队列操作。

  与内置条件队列不同的是,对于每个Lock,可以有任意数量的Condition对象。Condition对象继承了相关的Lock对象的公平性,对于公平的锁,线程会依照FIFO顺序从Condition.await中释放。

  下面程序给出了有界缓存的另一种实现,即使用两个Condition,分别为notFull和notEmpty,用于表示“非满”与“非空”两个条件谓词。当缓存为空时,take将阻塞并等待notEmpty,此时put向notEmpty发送信号,可以解除任何在take中阻塞的线程。

 /**
* 14.11 使用显式条件变量的有界缓存
* @ClassName: ConditionBoundedBuffer
* @author xingle
* @param <T>
* @date 2015-2-9 上午11:16:32
*/
public class ConditionBoundedBuffer<T> {
protected final Lock lock = new ReentrantLock();
//条件谓词:notFull (count < items.length)
private final Condition notFull = lock.newCondition();
//条件谓词:notEmpty (count > 0)
private final Condition notEmpty = lock.newCondition();
private static final int BUFFER_SIZE = 100;
@GuardedBy("lock")
private final T[] items = (T[]) new Object[BUFFER_SIZE];
@GuardedBy("lock")
private int tail,head,count; //阻塞并直到:notFull
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();
}
} //阻塞并直到:notEmpty
public T take() throws InterruptedException{
lock.lock();
try{
while(count==0)
notEmpty.await();
T x = items[head];
items[head] = null;
if(++head == items.length)
head = 0;
--count;
notEmpty.signal();
return x;
}finally{
lock.unlock();
}
} }

  ConditionBoundedBuffer的行为和BoundedBuffer相同,但它对条件队列的使用方式更容易理解——在分析使用多个Condition的类时,比分析一个使用单一内部队列加多个条件队列的类简单得多。通过将两个条件谓词分开并放到两个等待线程集中,Condition使其更容易满足单次通知的需求。signal比singalAll更高效,它能极大地减少在每次缓存操作中发生的上下文切换与锁请求的次数。

第2部分 实例

本示范简单模拟银行帐户的存取款活动,帐户余额大于等于取款金额时允许取款;帐户余额小于1000时允许存款(这与真实业务逻辑不符合,只是技术上需要才如此做的)。

1. 实体Account类

 /**
*
* @ClassName: Account
* @author xingle
* @date 2015-2-9 下午5:54:02
*/
public class Account {
private final Lock lock = new ReentrantLock(); // Condition对象
private final Condition condDeposit = lock.newCondition();
private final Condition condWithdraw = lock.newCondition();
private int balance; public Account(int balance){
this.balance = balance;
} //取钱
public void withdraw(int drawAmount) {
lock.lock();
try {
//如果账户余额不足,则取现方法阻塞
while (balance < drawAmount){
System.out.println("取钱阻塞");
condWithdraw.await();
}
//执行取钱
balance -= drawAmount;
System.out.println(Thread.currentThread().getName() + " 取钱:" + drawAmount + " 账户余额为:"+ balance);
//唤醒存钱线程
condDeposit.signal();
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
} //存钱
public void deposit(int depositAmount){
lock.lock();
try{
//如果账户余额大于1000,存钱方法阻塞
while(balance >1000){
System.out.println("存钱阻塞");
condDeposit.await();
}
balance += depositAmount;
System.out.println(Thread.currentThread().getName() + " 存款:" + depositAmount + " 账户余额为:"+ balance);
//唤醒取钱线程
condWithdraw.signal();
} catch(InterruptedException ex){
ex.printStackTrace();
}
finally{
lock.unlock();
}
}
}

2. 调用类(DepositDrawTest类)

 /**
*
* @ClassName: DepositDrawTest
* @author xingle
* @date 2015-2-10 上午10:38:44
*/
public class DepositDrawTest { public static void main(String[] args) {
// 创建一个账户,初始账户余额为0
Account acct = new Account(0);
new DrawThread("取钱者1", acct, 400).start();
new DrawThread("取钱者2", acct, 800).start();
new DepositThread("存款者甲", acct, 600).start();
new DepositThread("存款者乙", acct, 800).start();
new DepositThread("存款者丙", acct, 400).start(); }
} class DrawThread extends Thread {
// 模拟用户账户
private Account account;
// 每次取数数
private int drawAmount; public DrawThread(String name, Account account, int drawAmount) {
super(name);
this.account = account;
this.drawAmount = drawAmount;
} public void run() {
for (int i = 0; i < 3; i++) {
account.withdraw(drawAmount);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} class DepositThread extends Thread {
// 模拟用户账户
private Account account;
// 每次存钱数
private int depositAmount; public DepositThread(String name, Account account, int depositAmount) {
super(name);
this.account = account;
this.depositAmount = depositAmount;
} public void run() {
for (int i = 0; i < 3; i++) {
account.deposit(depositAmount);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

执行结果:

3. 总结

  1. 如果取款金额大于余额则不让取款,等存款队列继续存钱,余额足够支付时再让取款。
  2. 如果存款过多(大于1000),则存款不让存了,等取款队列把钱取走,余额降低到1000以下时,可以继续存款。
  3. 这样就允许多次连续取款(只要帐户有钱),多次连续存款(余额不能大于1000),而不是存款、取款依次调用。

参考:

1. Java:多线程,使用同步锁(Lock)时利用Condition类实现线程间通信

2. 怎么理解Condition

并发编程 19—— 显式的Conditon 对象的更多相关文章

  1. Java并发编程之显式锁机制

    我们之前介绍过synchronized关键字实现程序的原子性操作,它的内部也是一种加锁和解锁机制,是一种声明式的编程方式,我们只需要对方法或者代码块进行声明,Java内部帮我们在调用方法之前和结束时加 ...

  2. 使用显式的Lock对象取代synchronized关键字进行同步

    Java SE5的java.util.concurrent类库还包含有定义在java.util.concurrent.locks中的显式的互斥机制.Lock对象必须被显式地创建.锁定和释放.因此,它与 ...

  3. 《Java并发编程实战》第三章 对象的共享 读书笔记

    一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见 ...

  4. 《Java并发编程实战》第四章 对象的组合 读书笔记

    一.设计线程安全的类 在设计线程安全类的过程中,须要包括下面三个基本要素:  . 找出构成对象状态的全部变量.  . 找出约束状态变量的不变性条件.  . 建立对象状态的并发訪问管理策略. 分析对象的 ...

  5. Java编程思想学习笔记-使用显式的Lock对象

    若要保证后台线程在trylock()之前运行得到锁,可加“屏障”,如下1,2,3步,而trylock()不管设定时间与否都不会阻塞主线程而是立即返回: //: concurrency/AttemptL ...

  6. java并发编程读书笔记(1)-- 对象的共享

    1. 一些原则 RIM(Remote Method Invocation):远程方法调用 Race Condition:竞态条件 Servlet要满足多个线程的调用,必须是线程安全的 远程对象,即通过 ...

  7. JAVA并发编程实战---第三章:对象的共享(2)

    线程封闭 如果仅仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭,它是实现线程安全性的最简单的方式之一.当某个对象封闭在一个线程中时,这种方法将自动实现线程安全性,即使被封闭的对象本生不是线 ...

  8. java并发编程实战:第四章----对象的组合

    一.设计线程安全的类 找出构造对象状态的所有变量(若变量为引用类型,还包括引用对象中的域) 约束状态变量的不变性条件 建立对象状态的并发访问管理策略(规定了如何维护线程安全性) 1.收集同步需求(找出 ...

  9. Java并发编程学习笔记(三)——对象的组合

    重要概念: 1.在设计线程安全类的过程中,需要包含以下三个基本要素: (1)找出构成对象状态的所有变量. (2)找出约束状态变量的不变性条件. (3)建立对象状态的并发访问管理策略. 2.

随机推荐

  1. (地址)eclipse插件开发攻略的访问地址

    园子地址: http://www.cnblogs.com/liuzhuo/category/257208.html 关键字: Eclipse插件开发彻底攻略 eclipse插件开发基础篇之

  2. UE4 减少APK包的大小

    本文依据官方文档 Reducing APK Package Size整理而来,不过我会陆续添加自己减少包大小的心得. ETC1 纹理 当使用ETC1打Android包时,注意ETC1是不会压缩带Alp ...

  3. 20145320 《Java程序设计》第2周学习总结

    20145320 <Java程序设计>第2周学习总结 教材学习内容总结 3.1 类型.变量与运算符 基本类型 整数(short.int.long) .字节(byte) .浮点数(float ...

  4. 刨根问底U3D---Vector3 你到底是蔬菜呢还是水果呢?

    事情的起因还是因为一段代码,因为在做一个2D TileBase的游戏 所以需要有一个简单的 Tile坐标到世界坐标的变换 public static Vector3 GetTileWorldPosBy ...

  5. ubuntu15.04安装Chrome浏览器

    首先到: https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 下载最新的安装文件. 然后: sudo a ...

  6. RF--换行

    引自:http://blog.csdn.net/lvtingting2007/article/details/42173991

  7. Dynamics AX 2012 R2 安装额外的AOS

    众所周知,AX系统分为三层:Client,Application Server,Database Server. 我们添加额外的Application Server主要是出于以下两个原因: 使用多台服 ...

  8. Auty自动化测试框架第七篇——添加动作库和常量文件库

    [本文出自天外归云的博客园] 添加动作库 因为有很多调用的action类如果一直保存在utils中会让utils库不可维护,所以规定utils库中只放和框架本身有关的工具类,和脚本内容相关的工具类都放 ...

  9. EasyUI datebox 只读和取值

    <input id="dd" type="text" class="easyui-datebox" required="re ...

  10. Balsamiq Mockups 注册码

    Blacklist: Organization name: Rick DongSerial Key: eNrzzU/OLi0odswsqgnKTM5WcMnPS1eoMTQyMjexMDQyAIEa5 ...