《深入浅出 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() 添加一个许可,从而可能 ...
随机推荐
- 【免费】iPhone上最好用的短信群发软件: 高速短信4.1
免费的最新的联系人.群组.多人发送短信软件短信群发4.1已经出炉.欢迎下载! *归属地信息让你时时记着好友的地方,让陌生号码变得不陌生: *您能够选择最经常使用的联系人然后发送高速短信; *群联系人 ...
- 编译android-4.3.1_r源代码并刷到自己的Galaxy Nexus I9250真机上
编译android-4.3.1_r源代码并刷到自己的Galaxy Nexus I9250真机上 作者:雨水 日期:2014-04-30 编译源码的目的还是为了自己改动源码,然后还可以执行在相应的手机 ...
- STL 二分查找三兄弟(lower_bound(),upper_bound(),binary_search())
一:起因 (1)STL中关于二分查找的函数有三个:lower_bound .upper_bound .binary_search -- 这三个函数都运用于有序区间(当然这也是运用二分查找的前提),以 ...
- 将Ojective-C代码移植转换为Swift代码
相比于Objective-C,Swift语言更加简练.有时我们需要把原来写的一些Objective-C代码转换成Swift,下面总结了各种常见的情况. 1,构造函数的迁移 Objective-C为: ...
- 解决Myeclipse在port占用,导致tomcat无法启动。(Linux)
本文来源于:http://blog.csdn.net/svitter 引文:http://www.2cto.com/os/201305/209285.html { ubuntu查看占用某port的程序 ...
- Servlet和JSP读书笔记(二)
一. GenericServlet 1. 前面写的 Servlet和JSP学习笔记(一) 中的实例都是通过实现Servlet接口编写的,这样存在的问题就是:你必须实现Servlet中的所有方法,而不管 ...
- IP分类地址——a,b,c 类是如何划分的
今天IP网络使用32位地址,点分十进制格式,如172.16.0.0.地址格式:IP地址=网络地址+主机地址 或 IP地址=主机地址+子网地址+主机地址. IP地址类型 当互联网最初的设计,为了便于网络 ...
- Loser tree in Python | Christan Christens
Loser tree in Python | Christan Christens Loser tree in Python I am taking an Advanced Data Structur ...
- GNU libmicrohttpd 0.9.29 发布 - 开源中国社区
GNU libmicrohttpd 0.9.29 发布 - 开源中国社区 GNU libmicrohttpd 0.9.29 发布
- CString的部分实现剖析
一.CString初探: 在CString的实现中,其最基础的类结构如下: CString其实只有一个数据成员m_pszData,这个成员指向了字符串的首地址.但在MFC的具体实现中, m_pszDa ...