一、ReentrantLock 擁有Synchronized相同的併發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候
線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定,
若是使用 synchronized ,若是A不釋放,B將一直等下去,不能被中斷
若是 使用ReentrantLock,若是A不釋放,可使B在等待了足夠長的時間之後,中斷等待,而幹別的事情
ReentrantLock獲取鎖定與三種方式:
a) lock(), 若是獲取了鎖當即返回,若是別的線程持有鎖,當前線程則一直處於休眠狀態,直到獲取鎖
b) tryLock(), 若是獲取了鎖當即返回true,若是別的線程正持有鎖,當即返回false;
c)tryLock(long timeout,TimeUnit unit), 若是獲取了鎖定當即返回true,若是別的線程正持有鎖,會等待參數給定的時間,在等待的過程當中,若是獲取了鎖定,就返回true,若是等待超時,返回false;
d) lockInterruptibly:若是獲取了鎖定當即返回,若是沒有獲取鎖定,當前線程處於休眠狀態,直到或者鎖定,或者當前線程被別的線程中斷
二、synchronized是在JVM層面上實現的,不但能夠經過一些監控工具監控synchronized的鎖定,並且在代碼執行時出現異常,JVM會自動釋放鎖定,可是使用Lock則不行,lock是經過代碼實現的,要保證鎖定必定會被釋放,就必須將unLock()放到finally{}中
三、在資源競爭不是很激烈的狀況下,Synchronized的性能要優於ReetrantLock,可是在資源競爭很激烈的狀況下,Synchronized的性能會降低幾十倍,可是ReetrantLock的性能能維持常態;java
5.0的多線程任務包對於同步的性能方面有了很大的改進,在原有synchronized關鍵字的基礎上,又增長了ReentrantLock,以及各類Atomic類。瞭解其性能的優劣程度,有助與咱們在特定的情形下作出正確的選擇。程序員
整體的結論先擺出來:安全
synchronized:
在資源競爭不是很激烈的狀況下,偶爾會有同步的情形下,synchronized是很合適的。緣由在於,編譯程序一般會盡量的進行優化synchronize,另外可讀性很是好,無論用沒用過5.0多線程包的程序員都能理解。多線程
ReentrantLock:
ReentrantLock提供了多樣化的同步,好比有時間限制的同步,能夠被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,性能稍微比synchronized差點點。可是當同步很是激烈的時候,synchronized的性能一會兒能降低好幾十倍。而ReentrantLock確還能維持常態。併發
Atomic:
和上面的相似,不激烈狀況下,性能比synchronized略遜,而激烈的時候,也能維持常態。激烈的時候,Atomic的性能會優於ReentrantLock一倍左右。可是其有一個缺點,就是隻能同步一個值,一段代碼中只能出現一個Atomic的變量,多於一個同步無效。由於他不能在多個Atomic之間同步。dom
因此,咱們寫同步的時候,優先考慮synchronized,若是有特殊須要,再進一步優化。ReentrantLock和Atomic若是用的很差,不只不能提升性能,還可能帶來災難。ide
先貼測試結果:再貼代碼(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工具
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
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;
}
@Override
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){
super
( _id, _round, _threadNum, _cb);
}
/**
* synchronized關鍵字不在方法簽名裏面,因此不涉及重載問題
*/
@Override
long
getValue() {
try
{
lock.lock();
return
super
.countValue;
}
finally
{
lock.unlock();
}
}
@Override
void
sumValue() {
try
{
lock.lock();
super
.countValue+=preInit[index++%round];
}
finally
{
lock.unlock();
}
}
}
class
AtomicTest
extends
TestTemplate{
public
AtomicTest(String _id,
int
_round,
int
_threadNum,CyclicBarrier _cb){
super
( _id, _round, _threadNum, _cb);
}
@Override
/**
* synchronized關鍵字不在方法簽名裏面,因此不涉及重載問題
*/
long
getValue() {
return
super
.countValueAtmoic.get();
}
@Override
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) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
se.execute(
new
Runnable(){
public
void
run() {
getValue();
try
{
//每一個線程執行完同步方法後就等待
cb.await();
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch
(BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
try
{
//當前統計線程也wait,因此CyclicBarrier的初始值是threadNum*2+1
cb.await();
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch
(BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//全部線程執行完成以後,纔會跑到這一步
long
duration=System.nanoTime()-start;
out.println(id+
" = "
+duration);
}
}
|
摘自:性能
http://houlinyan.iteye.com/blog/1112535測試
http://zzhonghe.iteye.com/blog/826162