1、ReentrantLock 擁有Synchronized相同的并發性和記憶體語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候
線程A和B都要擷取對象O的鎖定,假設A擷取了對象O鎖,B将等待A釋放對O的鎖定,
如果使用 synchronized ,如果A不釋放,B将一直等下去,不能被中斷
如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而幹别的事情
ReentrantLock擷取鎖定與三種方式:
a) lock(), 如果擷取了鎖立即傳回,如果别的線程持有鎖,目前線程則一直處于休眠狀态,直到擷取鎖
b) tryLock(), 如果擷取了鎖立即傳回true,如果别的線程正持有鎖,立即傳回false;
d) lockInterruptibly:如果擷取了鎖定立即傳回,如果沒有擷取鎖定,目前線程處于休眠狀态,直到或者鎖定,或者目前線程被别的線程中斷
2、synchronized是在JVM層面上實作的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異 常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實作的,要保證鎖定一定會被釋放,就必須将unLock()放到 finally{}中
3、在資源競争不是很激烈的情況下,Synchronized的性能要優于ReetrantLock,但是在資源競争很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常态;
5.0的多線程任務包對于同步的性能方面有了很大的改進,在原有synchronized關鍵字的基礎上,又增加了ReentrantLock,以及各種Atomic類。了解其性能的優劣程度,有助與我們在特定的情形下做出正确的選擇。
總體的結論先擺出來:
synchronized:
在資源競争不是很激烈的情況下,偶爾會有同步的情形下,synchronized是很合适的。原因在于,編譯程式通常會盡可能的進行優化synchronize,另外可讀性非常好,不管用沒用過5.0多線程包的程式員都能了解。
ReentrantLock:
ReentrantLock 提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競 争不激烈的情形下,性能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的性能一下子能下降好幾十倍。而 ReentrantLock确還能維持常态。
Atomic:
和上面的類似,不激烈情況下,性能比synchronized略 遜,而激烈的時候,也能維持常态。激烈的時候,Atomic的性能會優于ReentrantLock一倍左右。但是其有一個缺點,就是隻能同步一個值,一 段代碼中隻能出現一個Atomic的變量,多于一個同步無效。因為他不能在多個Atomic之間同步。
是以,我們寫同步的時候,優先考慮synchronized,如果有特殊需要,再進一步優化。ReentrantLock和Atomic如果用的不好,不僅不能提高性能,還可能帶來災難。
先貼測試結果:再貼代碼(Atomic測試代碼不準确,一個同步中隻能有1個Actomic,這裡用了2個,但是這裡的測試隻看速度)
==========================
round:100000 thread:5
Sync = 35301694
Lock = 56255753
Atom = 43467535
round:200000 thread:10
Sync = 110514604
Lock = 204235455
Atom = 170535361
round:300000 thread:15
Sync = 253123791
Lock = 448577123
Atom = 362797227
round:400000 thread:20
Sync = 16562148262
Lock = 846454786
Atom = 667947183
round:500000 thread:25
Sync = 26932301731
Lock = 1273354016
Atom = 982564544
代碼如下:

package test.thread;
import static java.lang.System.out;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
public class TestSyncMethods {
public static void test(int round,int threadNum,CyclicBarrier cyclicBarrier){
new SyncTest("Sync",round,threadNum,cyclicBarrier).testTime();
new LockTest("Lock",round,threadNum,cyclicBarrier).testTime();
new AtomicTest("Atom",round,threadNum,cyclicBarrier).testTime();
}
public static void main(String args[]){
for(int i=0;i<5;i++){
int round=100000*(i+1);
int threadNum=5*(i+1);
CyclicBarrier cb=new CyclicBarrier(threadNum*2+1);
out.println("==========================");
out.println("round:"+round+" thread:"+threadNum);
test(round,threadNum,cb);
}
}
class SyncTest extends TestTemplate{
public SyncTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){
super( _id, _round, _threadNum, _cb);
@Override
/**
* synchronized關鍵字不在方法簽名裡面,是以不涉及重載問題
*/
synchronized long getValue() {
return super.countValue;
synchronized void sumValue() {
super.countValue+=preInit[index++%round];
class LockTest extends TestTemplate{
ReentrantLock lock=new ReentrantLock();
public LockTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){
long getValue() {
try{
lock.lock();
return super.countValue;
}finally{
lock.unlock();
void sumValue() {
super.countValue+=preInit[index++%round];
class AtomicTest extends TestTemplate{
public AtomicTest(String _id,int _round,int _threadNum,CyclicBarrier _cb){
long getValue() {
return super.countValueAtmoic.get();
void sumValue() {
super.countValueAtmoic.addAndGet(super.preInit[indexAtomic.get()%round]);
abstract class TestTemplate{
private String id;
protected int round;
private int threadNum;
protected long countValue;
protected AtomicLong countValueAtmoic=new AtomicLong(0);
protected int[] preInit;
protected int index;
protected AtomicInteger indexAtomic=new AtomicInteger(0);
Random r=new Random(47);
//任務栅欄,同批任務,先到達wait的任務挂起,一直等到全部任務到達制定的wait地點後,才能全部喚醒,繼續執行
private CyclicBarrier cb;
public TestTemplate(String _id,int _round,int _threadNum,CyclicBarrier _cb){
this.id=_id;
this.round=_round;
this.threadNum=_threadNum;
cb=_cb;
preInit=new int[round];
for(int i=0;i<preInit.length;i++){
preInit[i]=r.nextInt(100);
abstract void sumValue();
/*
* 對long的操作是非原子的,原子操作隻針對32位
* long是64位,底層操作的時候分2個32位讀寫,是以不是線程安全
abstract long getValue();
public void testTime(){
ExecutorService se=Executors.newCachedThreadPool();
long start=System.nanoTime();
//同時開啟2*ThreadNum個數的讀寫線程
for(int i=0;i<threadNum;i++){
se.execute(new Runnable(){
public void run() {
for(int i=0;i<round;i++){
sumValue();
}
//每個線程執行完同步方法後就等待
try {
cb.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
}
});
getValue();
//每個線程執行完同步方法後就等待
try {
//目前統計線程也wait,是以CyclicBarrier的初始值是threadNum*2+1
cb.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
//所有線程執行完成之後,才會跑到這一步
long duration=System.nanoTime()-start;
out.println(id+" = "+duration);
}
本文轉自快樂就好部落格園部落格,原文連結:http://www.cnblogs.com/happyday56/p/3756928.html,如需轉載請自行聯系原作者