ReentrantLock和內部鎖的性能對比(update)
ReentrantLock是jdk5引入的新的鎖機製,它與內部鎖(synchronize) 相同的並發性和內存語義,比如可重入加鎖語義。在中等或者更高負荷下,ReentrantLock有更好的性能,並且擁有可輪詢和可定時的請求鎖等高級功能。這個程序簡單對比了ReentrantLock公平鎖、ReentrantLock非公平鎖以及內部鎖的性能,從結果上看,非公平的ReentrantLock表現最好。內部鎖也僅僅是實現統計意義上的公平,結果也比公平的ReentrantLock好上很多。這個程序僅僅是計數,啟動N個線程,對同一個Counter進行遞增,顯然,這個遞增操作需要同步以保證原子性,采用不同的鎖來實現同步,然後查看結果。Counter接口:
public interface Counter {
public long getValue();
public void increment();
}
然後,首先使用我們熟悉的synchronize來實現同步:
public class SynchronizeBenchmark implements Counter {
private long count = 0;
public long getValue() {
return count;
}
public synchronized void increment() {
count++;
}
}
采用ReentrantLock的版本,切記要在finally中釋放鎖,這是與synchronize使用方式最大的不同,內部鎖jvm會自動幫你釋放鎖,而ReentrantLock需要你自己來處理。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockBeanchmark implements Counter {
private volatile long count = 0;
private Lock lock;
public ReentrantLockBeanchmark() {
// 使用非公平鎖,true就是公平鎖
lock = new ReentrantLock(false);
}
public long getValue() {
// TODO Auto-generated method stub
return count;
}
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
寫一個測試程序,使用CyclicBarrier來等待所有任務線程創建完畢以及所有任務線程計算完成,清單如下:
import java.util.concurrent.CyclicBarrier;
public class BenchmarkTest {
private Counter counter;
private CyclicBarrier barrier;
private int threadNum;
public BenchmarkTest(Counter counter, int threadNum) {
this.counter = counter;
barrier = new CyclicBarrier(threadNum + 1); //關卡計數=線程數+1
this.threadNum = threadNum;
}
public static void main(String args[]) {
new BenchmarkTest(new SynchronizeBenchmark(), 5000).test();
//new BenchmarkTest(new ReentrantLockBeanchmark(), 5000).test();
//new BenchmarkTest(new ReentrantLockBeanchmark(), 5000).test();
}
public void test() {
try {
for (int i = 0; i < threadNum; i++) {
new TestThread(counter).start();
}
long start = System.currentTimeMillis();
barrier.await(); // 等待所有任務線程創建
barrier.await(); // 等待所有任務計算完成
long end = System.currentTimeMillis();
System.out.println("count value:" + counter.getValue());
System.out.println("花費時間:" + (end - start) + "毫秒");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
class TestThread extends Thread {
private Counter counter;
public TestThread(final Counter counter) {
this.counter = counter;
}
public void run() {
try {
barrier.await();
for (int i = 0; i < 100; i++)
counter.increment();
barrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
分別測試一下,
將啟動的線程數限定為500,結果為:
公平ReentrantLock: 210 毫秒
非公平ReentrantLock : 39 毫秒
內部鎖: 39 毫秒
將啟動的線程數限定為1000,結果為:
公平ReentrantLock: 640 毫秒
非公平ReentrantLock : 81 毫秒
內部鎖: 60 毫秒
線程數不變,test方法中的循環增加到1000次,結果為:
公平ReentrantLock: 16715 毫秒
非公平ReentrantLock : 168 毫秒
內部鎖: 639 毫秒
將啟動的線程數增加到2000,結果為:
公平ReentrantLock: 1100 毫秒
非公平ReentrantLock: 125 毫秒
內部鎖: 130 毫秒
將啟動的線程數增加到3000,結果為:
公平ReentrantLock: 2461 毫秒
非公平ReentrantLock: 254 毫秒
內部鎖: 307 毫秒
啟動5000個線程,結果如下:
公平ReentrantLock: 6154 毫秒
非公平ReentrantLock: 623 毫秒
內部鎖: 720 毫秒
非公平ReentrantLock和內部鎖的差距,在jdk6上應該縮小了,據說jdk6的內部鎖機製進行了調整。
文章轉自莊周夢蝶 ,原文發布時間2007-09-14 17:15
最後更新:2017-05-18 10:32:51