[分享] Java之锁研究
Lock和synchronized5 M( r! f: u$ w
' p# W. a/ D6 q
JDK1.5以后,在锁机制方面引入了新的锁-Lock,在网上的说法都比较笼统,结合网上的信息和我的理解这里做个总结。
* l, i+ ^% ^ c8 b O) S
java现有的锁机制有两种实现方式,J.DK1.4前是通过synchronized实现,JDK1.5后加入java.util.concurrent.locks包下的各种lock(以下简称Lock)0 N. \/ D7 o! i) ^+ |) A/ o, L. o. @
先说说代码层的区别。/ k) Q. t* U$ F
synchronized:在代码里,synchronized类似“面向对象”,修饰类、方法、对象。+ Q( H- O2 J% ^7 m+ a
Lock:不作为修饰,类似“面向过程”,在方法中需要锁的时候lock,在结束的时候unlock(一般都在finally块里)。% r/ J5 l7 c$ K% r& [
例如代码:9 F0 q) m$ ^. g, F k; _$ r
Java代码 [url=][/url]
public
void method1() {
: {; y! c m7 _; u3 x i7 `! P1 ?1 F
synchronized(this){
System.out.println(1);
}
}
public% u; m0 Z% m$ Y! P0 U7 H, I5 K
void method2() {
Lock lock = new ReentrantLock();
lock.lock();
- P: g, n9 B' ^% Z
try{
System.out.println(2);
}finally{
lock.unlock();
}
} 1 j' F9 @% Z' E. T, g; n
其次说说性能。
相关的性能测试网上已经有很多,这里也直接拿来主义,给出结论:
在并发高是,luck性能优势很明显,在低并发时,synchronized也能取得优势。具体的临界范围比较难定论,下面会讨论。- n( n* Z! u# \- P
, d8 t" D! w! O; R4 d7 h9 d
现在来分析它们具体的区别。2 Y/ E# L4 ]# c6 n# ?& \4 c8 z1 H2 ]
锁都是 原子性 的,也可以理解为锁是否在使用的标记,并且比较和设置这个标记的操作是原子性的,不同硬件平台上的jdk实现锁的相关方法都是native的(比如park/unpark),所以不同平台上锁的精确度的等级由这些native的方法决定。所以网上经常可以看见的结论是“Lock比synchronized有更精确的原子操作”说的也是native方法(不得不感慨C才是硬件王道)。
( X8 L# Z8 C- }$ J- S9 q# H+ i
下面继续讨论怎么由代码层到native的过程。9 ^& s& z; T% k; R& T5 p. z$ T' q! `
1、所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。 只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。每当任务离开时,计数递减,当计数为0的时候,锁被完全释放。synchronized就是基于这个原理,同时synchronized靠某个对象的单一锁技术的次数来判断是否被锁,所以无需(也不能)人工干预锁的获取和释放。如果结合方法调用时的栈和框架(如果对方法的调用过程不熟悉建议看看
http://wupuyuan.iteye.com/blog/1157548),不难推测出synchronized原理是基于栈中的某对象来控制一个框架,所以对于synchronized有常用的优化是锁对象不锁方法。实际上synchronized作用于方法时,锁住的是“this”,作用于静态方法/属性时,锁住的是存在于永久带的CLASS,相当于这个CLASS的全局锁,锁作用于一般对象时,锁住的是对应代码块。在HotSpot中JVM实现中,锁有个专门的名字:对象监视器。
) `8 B: L* s- Q. Y+ P" G9 G
当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程
Contention List:所有请求锁的线程将被首先放置到该竞争队列,是个虚拟队列,不是实际的Queue的数据结构。
Entry List:EntryList与ContentionList逻辑上同属等待队列,ContentionList会被线程并发访问,为了降低对ContentionList队尾的争用,而建立EntryList。,Contention List中那些有资格成为候选人的线程被移到Entry List * E" f4 z4 h1 ~- [$ j
Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set/ j# e8 Q. z& S a! J5 G* n
OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck
Owner:获得锁的线程称为Owner
!Owner:释放锁的线程
2、Lock不同于synchronized面向对象,它基于栈中的框架而不是某个具体对象,所以Lock只需要在栈里设置锁的开始和结束(lock和unlock)的地方就行了(人工必须标明),不用关心框架大小对象的变化等等。这么做的好处是Lock能提供无条件的、可轮询的、定时的、可中断的锁获取操作,相对于synchronized来说,synchronized的锁的获取是释放必须在一个模块里,获取和释放的顺序必须相反,而Lock则可以在不同范围内获取释放,并且顺序无关。java.util.concurrent.locks下的锁类很类似,依赖于java.util.concurrent.AbstractQueuedSynchronizer,它们把所有的Lock接口操作都转嫁到Sync类上,这个类继承了AbstractQueuedSynchronizer,它同时还包含子2个类:NonfairSync 和FairSync 从名字上可以看的出是为了实现公平和非公平性。AbstractQueuedSynchronizer中把所有的的请求线程构成一个队列(一样也是虚拟的),具体的实现可以参考http://blog.csdn.net/chen77716/article/details/6641477#,这里我就不复制了。
3、从jdk的源代码来看,Lock和synchronized的源码基本相同,区别主要在维护的同步队列上。再往下深究就到了native方法了。( F! g. x5 v6 o) ^4 z( C
4、还有个改进我也想说下,其实很重要的。线程分阻塞(wait)和非阻塞状态,阻塞状态由操作系统(linux、windows等)完成,当前一个被“锁”的线程执行完毕后,有可能在后续的线程队列里还没分配出一个获取锁而被“唤醒”的非阻塞线程,即所有线程还都是阻塞状态时,就被系统调度(进入内核的线程是阻塞的),这样会导致内核在用户态和内核态之间来回接换,严重影响锁的性能。在jdk1.6以前主要靠自旋锁来解决,原理是在前一个线程结束后,争用线程可以做一个空循环,继续占有CPU,等待取锁的机会。当然这样做显然也是浪费时间,只是在两种浪费中选取浪费少的…… jdk1.6后引入了偏向锁,当线程第一次获得了监视对象,之后让监视对象“偏向”这个线程,之后的多次调用则可以避免CAS操作,等于是置了一临时变量来记录位置(类似索引比较)。详细的就涉及到汇编指令了,我也就没太深究,偏向锁性能优于自旋锁,但是还是没有达到HotSpot认为的最佳时间(一个线程上下文切换的时间)。7 ^9 p* {1 G e+ w7 Y& q( T
综合来看对于所有的高并发情况,采用Lock加锁是最优选择,但是由于历史遗留等问题,synchronized也还是不能完全被淘汰,同时,在低并发情况下,synchronized的性能还是比Lock好的。
最后还是希望各位拍砖。
转自:http://tech.techweb.com.cn/thread-512489-1-1.html
java并发ppt:http://wenku.baidu.com/view/d87a1d10f18583d04964594a.html
java并发编程实践电子书:http://www.linuxidc.com/Linux/2011-07/38239.htm
分享到:
相关推荐
这份资料包含了关于Java并发编程的博客和网页,可以提供深入的理解和实践指导。 在Java并发编程中,首先要理解的是线程的基本概念。线程是程序执行的最小单元,一个进程可以包含多个线程,它们共享同一块内存空间,...
《Java并发编程实战》是Java并发编程领域的一本经典著作,它深入浅出地介绍了如何在Java平台上进行高效的多线程编程。这本书的源码提供了丰富的示例,可以帮助读者更好地理解书中的理论知识并将其应用到实际项目中。...
综合来看,该书不仅适合于对Java并发编程感兴趣的初学者,同样也适合有经验的开发者,作为一本参考资料和实践指南,读者可以通过它来加深对Java并发特性的理解和应用。书中丰富的案例分析和代码示例将有助于读者更...
Java并发编程是Java开发中的重要领域,特别是在多核处理器和分布式系统中,高效地利用并发可以极大地提升程序的性能和响应速度。以下是对标题和描述中所提及的几个知识点的详细解释: 1. **线程与并发** - **线程*...
《Java并发编程实战》是一本深入探讨Java平台并发编程的权威指南。这本书旨在帮助开发者理解和掌握在Java环境中创建高效、可扩展且可靠的多线程应用程序的关键技术和实践。它涵盖了从基本概念到高级主题的广泛内容,...
《Java并发编程艺术》这本书深入探讨了Java平台上的并发编程技术。并发编程是现代多核处理器环境下提升软件性能的关键手段,而Java语言提供了丰富的工具和API来支持这一领域。本书旨在帮助开发者理解和掌握如何在...
这份“java并发编程内部分享PPT”显然是一个深入探讨这一主题的资料,旨在帮助开发者理解并掌握Java并发编程的核心概念和技术。 在Java并发编程中,首先我们需要了解的基本概念是线程。线程是操作系统分配CPU时间的...
JAVA并发编程艺术 高清pdf : 1.并发变成的挑战 2. java并发机制的底层实现原理 3. java 内存模型 4. java并发编程基础 5.java中的锁。。。。。。。
《Java 并发编程实战》是一本专注于Java并发编程的权威指南,对于任何希望深入了解Java多线程和并发控制机制的开发者来说,都是不可或缺的参考资料。这本书深入浅出地介绍了如何在Java环境中有效地管理和控制并发...
《Java并发编程实践》是一本深入探讨Java多线程编程的经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowles和David Holmes等专家共同编写。这本书全面介绍了Java平台上的并发编程技术,是Java开发...
Java并发编程是软件开发中的一个关键领域,尤其是在大型企业级应用和分布式系统中。通过学习相关的书籍,开发者可以深入...购买并阅读相关的专业书籍,如《Java并发编程实战》等,将有助于你系统地掌握这一领域的知识。
### Java并发编程实战知识点概述 #### 一、Java并发特性详解 在《Java并发编程实战》这本书中,作者深入浅出地介绍了Java 5.0和Java 6中新增的并发特性。这些特性旨在帮助开发者更高效、安全地编写多线程程序。书中...
JAVA并发编程实践中文版 英文版 原书源码 带书签 java_concurrency_in_practice.pdf 英文版还是不错的,但是中文版的译者典型的没有技术功底,介绍上说什么专家, 翻译的非常差劲,有些句子都不通顺,都不知道自己去...
《JAVA并发编程艺术》是Java开发者深入理解和掌握并发编程的一本重要著作,它涵盖了Java并发领域的核心概念和技术。这本书详细阐述了如何在多线程环境下有效地编写高效、可靠的代码,对于提升Java程序员的技能水平...
Java并发编程实践是Java开发中不可或缺的一个领域,它涉及到如何高效、正确地处理多线程环境中的任务。这本书的读书笔记涵盖了多个关键知识点,旨在帮助读者深入理解Java并发编程的核心概念。 1. **线程和进程的...
#### 一、Java并发概述 自Java诞生之初,其设计者就赋予了该语言强大的并发处理能力。Java语言内置了对线程和锁的支持,这使得开发者能够轻松地编写多线程应用程序。本文旨在帮助Java开发者深入理解并发的核心概念...
在Java编程领域,并发编程是一项核心技能,尤其是在大型系统或分布式应用中,高效地处理多线程和并发操作是至关重要的。...这份资料对于理解Java并发原理、优化并发代码和解决并发问题具有极大的价值。
《JAVA并发编程实践》这本书是Java开发者深入理解并发编程的重要参考资料。它涵盖了Java并发的核心概念、工具和最佳实践,旨在帮助读者在多线程环境下编写高效、安全的代码。 并发编程是现代软件开发中的关键技能,...