《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock
转会:http://www.blogjava.net/xylz/archive/2010/07/05/325274.html
前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来总体说明。
从这一章開始花少量的篇幅谈谈锁机制。
上一个章节 中谈到了锁机制,而且针对于原子操作谈了一些相关的概念和设计思想。接下来的文章中。尽可能的深入研究锁机制,而且理解里面的原理和实际应用场合。
虽然synchronized在语法上已经足够简单了。在JDK 5之前仅仅能借助此实现,可是因为是独占锁。性能却不高,因此JDK 5以后就開始借助于JNI来完毕更高级的锁实现。
JDK 5中的锁是接口java.util.concurrent.locks.Lock 。
另外java.util.concurrent.locks.ReadWriteLock 提供了一对可供读写并发的锁。依据前面的规则,我们从java.util.concurrent.locks.Lock 的API開始。
void lock();
获取锁。
假设锁不可用。出于线程调度目的,将禁用当前线程。而且在获得锁之前。该线程将一直处于休眠状态。
void lockInterruptibly() throws InterruptedException;
假设当前线程未被中断。则获取锁。
假设锁可用。则获取锁,并马上返回。
假设锁不可用,出于线程调度目的,将禁用当前线程,而且在发生下面两种情况之中的一个曾经。该线程将一直处于休眠状态:
- 锁由当前线程获得;或者
- 其它某个线程中断 当前线程,而且支持对锁获取的中断。
假设当前线程:
- 在进入此方法时已经设置了该线程的中断状态;或者
- 在获取锁时被中断 ,而且支持对锁获取的中断,
则将抛出 InterruptedException 。并清除当前线程的已中断状态。
Condition newCondition();
返回绑定到此 Lock 实例的新 Condition 实例。下一小节中会重点谈Condition,此处不做过多的介绍。
boolean tryLock();
仅在调用时锁为空暇状态才获取该锁。
假设锁可用,则获取锁,并马上返回值 true 。假设锁不可用。则此方法将马上返回值 false 。
通常对于那些不是必须获取锁的操作可能实用。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
假设锁在给定的等待时间内空暇,而且当前线程未被中断,则获取锁。
假设锁可用,则此方法将马上返回值 true 。假设锁不可用,出于线程调度目的,将禁用当前线程,而且在发生下面三种情况之中的一个前,该线程将一直处于休眠状态:
- 锁由当前线程获得;或者
- 其它某个线程中断当前线程,而且支持对锁获取的中断;或者
- 已超过指定的等待时间
假设获得了锁,则返回值 true 。
假设当前线程:
- 在进入此方法时已经设置了该线程的中断状态;或者
- 在获取锁时被中断,而且支持对锁获取的中断。
则将抛出 InterruptedException 。并会清除当前线程的已中断状态。
假设超过了指定的等待时间。则将返回值 false 。假设 time 小于等于 0,该方法将全然不等待。
void unlock();
释放锁。
相应于lock()、tryLock()、tryLock(xx)、lockInterruptibly()等操作,假设成功的话应该相应着一个unlock(),这样能够避免死锁或者资源浪费。
相对于比較空洞的API。来看一个实际的样例。以下的代码实现了一个类似于AtomicInteger的操作。
package xylz.study.concurrency.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class AtomicIntegerWithLock {
private int value;
private Lock lock = new ReentrantLock();
public AtomicIntegerWithLock() {
super();
}public AtomicIntegerWithLock(int value) {
this.value = value;
}public final int get() {
lock.lock();
try {
return value;
} finally {
lock.unlock();
}
}public final void set(int newValue) {
lock.lock();
try {
value = newValue;
} finally {
lock.unlock();
}}
public final int getAndSet(int newValue) {
lock.lock();
try {
int ret = value;
value = newValue;
return ret;
} finally {
lock.unlock();
}
}public final boolean compareAndSet(int expect, int update) {
lock.lock();
try {
if (value == expect) {
value = update;
return true;
}
return false;
} finally {
lock.unlock();
}
}public final int getAndIncrement() {
lock.lock();
try {
return value++;
} finally {
lock.unlock();
}
}public final int getAndDecrement() {
lock.lock();
try {
return value--;
} finally {
lock.unlock();
}
}public final int incrementAndGet() {
lock.lock();
try {
return ++value;
} finally {
lock.unlock();
}
}public final int decrementAndGet() {
lock.lock();
try {
return --value;
} finally {
lock.unlock();
}
}public String toString() {
return Integer.toString(get());
}
}
类AtomicIntegerWithLock 是线程安全的,此结构中大量使用了Lock对象的lock/unlock方法对。相同可以看到的是对于自增和自减操作使用了++/--。之所以可以保证线程安全,是由于Lock对象的lock()方法保证了仅仅有一个线程可以仅仅有此锁。须要说明的是对于不论什么一个lock()方法,都须要一个unlock()方法与之对于,通常情况下为了保证unlock方法总是可以得到运行,unlock方法被置于finally块中。另外这里使用了java.util.concurrent.locks.ReentrantLock.ReentrantLock 对象。下一个小节中会详细描写叙述此类作为Lock的唯一实现是怎样设计和实现的。
虽然synchronized实现Lock的同样语义,而且在语法上比Lock要简单多。可是前者却比后者的开销要大得多。做一个简单的測试。
public static void main(String[] args) throws Exception{
final int max = 10;
final int loopCount = 100000;
long costTime = 0;
for (int m = 0; m < max; m++) {
long start1 = System.nanoTime();
final AtomicIntegerWithLock value1 = new AtomicIntegerWithLock(0);
Thread[] ts = new Thread[max];
for(int i=0;i<max;i++) {
ts[i] = new Thread() {
public void run() {
for (int i = 0; i < loopCount; i++) {
value1.incrementAndGet();
}
}
};
}
for(Thread t:ts) {
t.start();
}
for(Thread t:ts) {
t.join();
}
long end1 = System.nanoTime();
costTime += (end1-start1);
}
System.out.println("cost1: " + (costTime));
//
System.out.println();
costTime = 0;
//
final Object lock = new Object();
for (int m = 0; m < max; m++) {
staticValue=0;
long start1 = System.nanoTime();
Thread[] ts = new Thread[max];
for(int i=0;i<max;i++) {
ts[i] = new Thread() {
public void run() {
for (int i = 0; i < loopCount; i++) {
synchronized(lock) {
++staticValue;
}
}
}
};
}
for(Thread t:ts) {
t.start();
}
for(Thread t:ts) {
t.join();
}
long end1 = System.nanoTime();
costTime += (end1-start1);
}
//
System.out.println("cost2: " + (costTime));
}static int staticValue = 0;
在这个样例中每次启动10个线程,每一个线程计算100000次自增操作,反复測试10次,以下是某此測试的结果:
cost1: 624071136
cost2: 2057847833
虽然上面的例子是不是很正规的测试案例,然而,上述例子是为了说明,Lock性能比synchronized更好。那么假设可以随时使用Lock替代synchronized这是一个明智的选择。
《深入浅出 Java Concurrency》—锁紧机构(一)Lock与ReentrantLock的更多相关文章
- 深入浅出 Java Concurrency (8): 加锁的原理 (Lock.lock)
接上篇,这篇从Lock.lock/unlock开始.特别说明在没有特殊情况下所有程序.API.文档都是基于JDK 6.0的. public void java.util.concurrent.lock ...
- 深入浅出 Java Concurrency 锁机制 : AQS
转载:http://www.blogjava.net/xylz/archive/2010/07/06/325390.html 在理解J.U.C原理以及锁机制之前,我们来介绍J.U.C框架最核心也是最复 ...
- [转] 多线程 《深入浅出 Java Concurrency》目录
http://ifeve.com/java-concurrency-thread-directory/ synchronized使用的内置锁和ReentrantLock这种显式锁在java6以后性能没 ...
- 《深入浅出 Java Concurrency》目录
最近在学习J.U.C,看到一个大神 关于这个系列写的非常精辟,由于想做笔记,故系列转载并记录之. 原文:http://www.blogjava.net/xylz/archive/2010/07/08/ ...
- 深入浅出 Java Concurrency - 目录 [转]
这是一份完整的Java 并发整理笔记,记录了我最近几年学习Java并发的一些心得和体会. J.U.C 整体认识 原子操作 part 1 从AtomicInteger开始 原子操作 part 2 数组. ...
- 深入浅出 Java Concurrency (6): 锁机制 part 1 Lock与ReentrantLock
前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来整体说明.从这一章开始花少量的篇幅谈谈锁机制. 上一个章节中谈到了锁机制,并且针对于原子操作谈了一些相关的概念 ...
- 深入浅出 Java Concurrency (9): 锁机制 part 4 锁释放与条件变量 (Lock.unlock And Condition)
本小节介绍锁释放Lock.unlock(). Release/TryRelease unlock操作实际上就调用了AQS的release操作,释放持有的锁. public final boolean ...
- 深入浅出 Java Concurrency (15): 锁机制 part 10 锁的一些其它问题
主要谈谈锁的性能以及其它一些理论知识,内容主要的出处是<Java Concurrency in Practice>,结合自己的理解和实际应用对锁机制进行一个小小的总结. 首先需要强调的 ...
- 深入浅出 Java Concurrency (12): 锁机制 part 7 信号量(Semaphore)
Semaphore 是一个计数信号量.从概念上讲,信号量维护了一个许可集.如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可.每个 release() 添加一个许可,从而可能 ...
随机推荐
- 解决 Android SDK Manager不能下载旧版本的sdk的问题
解决无法使用Android SDK Manager下载SDK开发包的解决办法. 当我们在官网下载google的集成ADT,也就是adt-bundle-linux-x86.zip开发包,进行解压, 打 ...
- 细说UI线程和Windows消息队列
在 Windows应用程序中,窗体是由一种称为“ UI线程( User Interface Thread)”的特殊类型的线程创建的. 首先, UI线程是一种“线程”,所以它具有一个线程应该具有的所有特 ...
- Android studio导入Eclipse项目,和一些错误的解决
Android studio导入Eclipse开发的项目步骤如下 如果已经打开Android studio的话就选择你已打开的项目,关闭然后导入 开始导入 导入完成. 2.项目出错 Error:(13 ...
- 用Swift开发二维码扫描器教程
(原文:Building a QR Code Reader in Swift 作者:Simon Ng 译者:xiaoying )我相信大多数人都知道二维码(QR code)是什么,如果你对这个概念还不 ...
- MySQL 通配符学习总结
MySQL 通配符 SQL您同意使用模式匹配"_"无论单个字符相匹配,和"%"匹配随意数目字符(包含零个字符). 在 MySQL中.SQL的模式缺省是忽略大写和 ...
- 第四章 Spring与JDBC的整合
这里选择的是mysql数据库. 4.1引入aop.tx的命名空间 为了事务配置的需要,我们引入aop.tx的命名空间 <?xml version="1.0" encoding ...
- OCA读书笔记(10) - 管理UNDO数据
Undo自动管理与手动管理 undo段自动管理SQL> show parameter undo_management 将undo段改为手工管理SQL> alter system set u ...
- 事件总线帧---Otto
我们如果这样一种业务场景.如今在做一款及时聊天应用,我们在聊天页面进行收发信息.同一时候也要实时更新前一页面的聊天记录,这时我们该怎样去实现?说说我曾经的实现策略.我使用的是广播接收器BroadCas ...
- iOS8:把这些七招APP哭
6月3日.苹果发布了新一代的高配置手机操作系统iOS 8,我们看到了很多新的功能和引人注目的新变化.它为开发人员提供了许多其他更酷能力发展.第三方输入法也开放,这使得国内的百度.搜狗输入法是不过高兴的 ...
- VMware vSphere服务器虚拟化实验十一高可用性之三Fault Tolerance
VMware vSphere服务器虚拟化实验十一高可用性之三Fault Tole ...