爲了比較一下ReentrantLock和synchronized的性能,作了一下性能測試:java
得出結論:算法
(1)使用Lock的性能比使用synchronized關鍵字要提升4~5倍;多線程
(2)使用信號量實現同步的速度大約比synchronized要慢10~20%;併發
(3)使用atomic包的AtomicInter速度是比Lock要快1一個數量級。框架
ReentrantLock 類
java.util.concurrent.lock 中的 Lock 框架是鎖定的一個抽象,它容許把鎖定的實現做爲 Java 類,而不是做爲語言的特性來實現。這就爲 Lock 的多種實現留下了空間,各類實現可能有不一樣的調度算法、性能特性或者鎖定語義。ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的併發性和內存語義,可是添加了相似鎖投票、定時鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭用狀況下更佳的性能。(換句話說,當許多線程都想訪問共享資源時,JVM 能夠花更少的時候來調度線程,把更多時間用在執行線程上。) ide
reentrant 鎖意味着什麼呢?簡單來講,它有一個與鎖相關的獲取計數器,若是擁有鎖的某個線程再次獲得鎖,那麼獲取計數器就加1,而後鎖須要被釋放兩次才能得到真正釋放。這模仿了 synchronized 的語義;若是線程進入由線程已經擁有的監控器保護的 synchronized 塊,就容許線程繼續進行,當線程退出第二個(或者後續)synchronized 塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個 synchronized 塊時,才釋放鎖。 性能
在查看清單 1 中的代碼示例時,能夠看到 Lock 和 synchronized 有一點明顯的區別 —— lock 必須在 finally 塊中釋放。不然,若是受保護的代碼將拋出異常,鎖就有可能永遠得不到釋放!這一點區別看起來可能沒什麼,可是實際上,它極爲重要。忘記在 finally 塊中釋放鎖,可能會在程序中留下一個定時bomb,當有一天bomb爆炸時,您要花費很大力氣纔有找到源頭在哪。而使用同步,JVM 將確保鎖會得到自動釋放。 測試
Test的源碼ui
view plaincopy to clipboardprint?
01.public abstract class Test {
02. protected String id;
03. protected CyclicBarrier barrier;
04. protected long count;
05. protected int threadNum;
06. protected ExecutorService executor;
07.
08. public Test(String id, CyclicBarrier barrier, long count, int threadNum,
09. ExecutorService executor) {
10. this.id = id;
11. this.barrier = barrier;
12. this.count = count;
13. this.threadNum = threadNum;
14. this.executor = executor;
15. }
16.
17. public void startTest() {
18.
19. long start = System.currentTimeMillis();
20.
21. for (int j = 0; j < threadNum; j++) {
22. executor.execute(new Thread() {
23. @Override
24. public void run() {
25. for (int i = 0; i < count; i++) {
26. test();
27. }
28.
29. try {
30. barrier.await();
31.
32. } catch (InterruptedException e) {
33. e.printStackTrace();
34. } catch (BrokenBarrierException e) {
35. e.printStackTrace();
36. }
37. }
38. });
39. }
40.
41. try {
42. barrier.await();
43. } catch (InterruptedException e) {
44. e.printStackTrace();
45. } catch (BrokenBarrierException e) {
46. e.printStackTrace();
47. }
48.
49. // 全部線程執行完成以後,纔會跑到這一步
50. long duration = System.currentTimeMillis() - start;
51. System.out.println(id + " = " + duration);
52. }
53.
54. protected abstract void test();
55.}
public abstract class Test {
protected String id;
protected CyclicBarrier barrier;
protected long count;
protected int threadNum;
protected ExecutorService executor;this
public Test(String id, CyclicBarrier barrier, long count, int threadNum,
ExecutorService executor) {
this.id = id;
this.barrier = barrier;
this.count = count;
this.threadNum = threadNum;
this.executor = executor;
}
public void startTest() {
long start = System.currentTimeMillis();
for (int j = 0; j < threadNum; j++) {
executor.execute(new Thread() {
@Override
public void run() {
for (int i = 0; i < count; i++) {
test();
}
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
// 全部線程執行完成以後,纔會跑到這一步
long duration = System.currentTimeMillis() - start;
System.out.println(id + " = " + duration);
}
protected abstract void test();
}
測試類ReentreLockTest 源碼
view plaincopy to clipboardprint?
01.import thread.test.Test;
02.
03.public class ReentreLockTest {
04. private static long COUNT = 1000000;
05. private static Lock lock = new ReentrantLock();
06. private static long lockCounter = 0;
07. private static long syncCounter = 0;
08. private static long semaCounter = 0;
09. private static AtomicLong atomicCounter = new AtomicLong(0);
10. private static Object syncLock = new Object();
11. private static Semaphore mutex = new Semaphore(1);
12.
13. public static void testLock(int num, int threadCount) {
14.
15. }
16.
17. static long getLock() {
18. lock.lock();
19. try {
20. return lockCounter;
21. } finally {
22. lock.unlock();
23. }
24. }
25.
26. static long getSync() {
27. synchronized (syncLock) {
28. return syncCounter;
29. }
30. }
31.
32. static long getAtom() {
33. return atomicCounter.get();
34. }
35.
36. static long getSemaphore() throws InterruptedException {
37. mutex.acquire();
38.
39. try {
40. return semaCounter;
41. } finally {
42. mutex.release();
43. }
44. }
45.
46. static long getLockInc() {
47. lock.lock();
48. try {
49. return ++lockCounter;
50. } finally {
51. lock.unlock();
52. }
53. }
54.
55. static long getSyncInc() {
56. synchronized (syncLock) {
57. return ++syncCounter;
58. }
59. }
60.
61. static long getAtomInc() {
62. return atomicCounter.getAndIncrement();
63. }
64.
65. static class SemaTest extends Test {
66.
67. public SemaTest(String id, CyclicBarrier barrier, long count,
68. int threadNum, ExecutorService executor) {
69. super(id, barrier, count, threadNum, executor);
70. }
71.
72. @Override
73. protected void test() {
74. try {
75. getSemaphore();
76. } catch (InterruptedException e) {
77. e.printStackTrace();
78. }
79. }
80.
81. }
82.
83. static class LockTest extends Test {
84.
85. public LockTest(String id, CyclicBarrier barrier, long count,
86. int threadNum, ExecutorService executor) {
87. super(id, barrier, count, threadNum, executor);
88. }
89.
90. @Override
91. protected void test() {
92. getLock();
93. }
94.
95. }
96.
97. static class SyncTest extends Test {
98.
99. public SyncTest(String id, CyclicBarrier barrier, long count,
100. int threadNum, ExecutorService executor) {
101. super(id, barrier, count, threadNum, executor);
102. }
103.
104. @Override
105. protected void test() {
106. getSync();
107. }
108.
109. }
110.
111. static class AtomicTest extends Test {
112.
113. public AtomicTest(String id, CyclicBarrier barrier, long count,
114. int threadNum, ExecutorService executor) {
115. super(id, barrier, count, threadNum, executor);
116. }
117.
118. @Override
119. protected void test() {
120. getAtom();
121. }
122.
123. }
124.
125. public static void test(String id, long count, int threadNum,
126. ExecutorService executor) {
127.
128. final CyclicBarrier barrier = new CyclicBarrier(threadNum + 1,
129. new Thread() {
130.
131. @Override
132. public void run() {
133.
134. }
135. });
136.
137. System.out.println("==============================");
138. System.out.println("count = " + count + "\t" + "Thread Count = "
139. + threadNum);
140.
141. new LockTest("Lock ", barrier, COUNT, threadNum, executor).startTest();
142. new SyncTest("Sync ", barrier, COUNT, threadNum, executor).startTest();
143. new AtomicTest("Atom ", barrier, COUNT, threadNum, executor)
144. .startTest();
145. new SemaTest("Sema ", barrier, COUNT, threadNum, executor)
146. .startTest();
147. System.out.println("==============================");
148. }
149.
150. public static void main(String[] args) {
151. for (int i = 1; i < 5; i++) {
152. ExecutorService executor = Executors.newFixedThreadPool(10 * i);
153. test("", COUNT * i, 10 * i, executor);
154. }
155. }
156.}
import thread.test.Test;
public class ReentreLockTest {
private static long COUNT = 1000000;
private static Lock lock = new ReentrantLock();
private static long lockCounter = 0;
private static long syncCounter = 0;
private static long semaCounter = 0;
private static AtomicLong atomicCounter = new AtomicLong(0);
private static Object syncLock = new Object();
private static Semaphore mutex = new Semaphore(1);
public static void testLock(int num, int threadCount) {
}
static long getLock() {
lock.lock();
try {
return lockCounter;
} finally {
lock.unlock();
}
}
static long getSync() {
synchronized (syncLock) {
return syncCounter;
}
}
static long getAtom() {
return atomicCounter.get();
}
static long getSemaphore() throws InterruptedException {
mutex.acquire();
try {
return semaCounter;
} finally {
mutex.release();
}
}
static long getLockInc() {
lock.lock();
try {
return ++lockCounter;
} finally {
lock.unlock();
}
}
static long getSyncInc() {
synchronized (syncLock) {
return ++syncCounter;
}
}
static long getAtomInc() {
return atomicCounter.getAndIncrement();
}
static class SemaTest extends Test {
public SemaTest(String id, CyclicBarrier barrier, long count,
int threadNum, ExecutorService executor) {
super(id, barrier, count, threadNum, executor);
}
@Override
protected void test() {
try {
getSemaphore();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class LockTest extends Test {
public LockTest(String id, CyclicBarrier barrier, long count,
int threadNum, ExecutorService executor) {
super(id, barrier, count, threadNum, executor);
}
@Override
protected void test() {
getLock();
}
}
static class SyncTest extends Test {
public SyncTest(String id, CyclicBarrier barrier, long count,
int threadNum, ExecutorService executor) {
super(id, barrier, count, threadNum, executor);
}
@Override
protected void test() {
getSync();
}
}
static class AtomicTest extends Test {
public AtomicTest(String id, CyclicBarrier barrier, long count,
int threadNum, ExecutorService executor) {
super(id, barrier, count, threadNum, executor);
}
@Override
protected void test() {
getAtom();
}
}
public static void test(String id, long count, int threadNum,
ExecutorService executor) {
final CyclicBarrier barrier = new CyclicBarrier(threadNum + 1,
new Thread() {
@Override
public void run() {
}
});
System.out.println("==============================");
System.out.println("count = " + count + "\t" + "Thread Count = "
+ threadNum);
new LockTest("Lock ", barrier, COUNT, threadNum, executor).startTest();
new SyncTest("Sync ", barrier, COUNT, threadNum, executor).startTest();
new AtomicTest("Atom ", barrier, COUNT, threadNum, executor)
.startTest();
new SemaTest("Sema ", barrier, COUNT, threadNum, executor)
.startTest();
System.out.println("==============================");
}
public static void main(String[] args) {
for (int i = 1; i < 5; i++) {
ExecutorService executor = Executors.newFixedThreadPool(10 * i);
test("", COUNT * i, 10 * i, executor);
}
}
}
結果
view plaincopy to clipboardprint? 01.============================== 02.count = 1000000 Thread Count = 10 03.Lock = 953 04.Sync = 3781 05.Atom = 78 06.Sema = 4922 07.============================== 08.============================== 09.count = 2000000 Thread Count = 20 10.Lock = 1906 11.Sync = 8469 12.Atom = 172 13.Sema = 9719 14.============================== 15.============================== 16.count = 3000000 Thread Count = 30 17.Lock = 2890 18.Sync = 12641 19.Atom = 219 20.Sema = 15015 21.============================== 22.============================== 23.count = 4000000 Thread Count = 40 24.Lock = 3844 25.Sync = 17141 26.Atom = 343 27.Sema = 19782 28.==============================