不同:
synchronized获得锁和释放的方式都是在 块结构中,当获取多个锁的时候必须以相反的顺序释放,并且是 自动解锁。
Lock是JDK1.5以后引进的,它相比synchronized关键词要更 灵活,可用范围更 广泛。
用法:
我们来看一个计数器的例子来比较这两者的不同:
1. synchronized
1
2
3
4
5
6
7
8
9
10
11
|
public
class
Counter {
private
int
count =
0
;
public
int
inc() {
synchronized
(
this
) {
return
++count;
}
}
}
|
//加了synchronized关键词后,count每次在块中只能被同一个进程加数。
//我们再来看下使用 Lock是如何实现的
2. Lock
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
Counter {
private
Lock lock =
new
Lock();
private
int
count =
0
;
public
int
inc() {
lock.lock();
int
newCount = ++count;
lock.unlock();
return
newCount;
}
}
|
//从调用Lock方法之后lock的实例就被锁定,直道被调用unlock才解锁。
性能比较:
下面是在我电脑上跑出的结果:Threads | 1x synch | 1x Lock | 1x AtomicInteger | 2x synch | 2x Lock | 2x AtomicInteger |
---|---|---|---|---|---|---|
1 | 1.797 | 2.175 | 0.947 | 3.246 | 4.111 | 1.703 |
2 | 8.685 | 4.134 | 1.889 | 13.144 | 4.901 | 1.949 |
4 | 7.942 | 3.040 | 1.735 | 13.182 | 4.960 | 1.945 |
8 | 7.648 | 3.011 | 1.894 | 13.287 | 4.979 | 1.951 |
16 | 8.017 | 2.974 | 1.735 | 13.040 | 4.573 | 1.950 |
32 | 7.908 | 2.958 | 1.777 | 13.059 | 4.845 | 1.958 |
64 | 7.853 | 2.972 | 1.878 | 13.316 | 5.004 | 1.954 |
从结果上看, 当线程数越多时Lock的效率越高。
synchronized和Lock应该用哪一个,Sun没有官方的说法,也没有deprecate synchronized.从程序控制角度来说,我觉得哪个方便用哪个就可以了。
下面是测试代码,大家也可以自己跑一下:
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
|
/*
* Copyright (c) 2011. By Peter Lawrey
*
*/
package
com.javasleep.threads;
import
org.junit.Test;
import
java.util.Map;
import
java.util.TreeMap;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.TimeUnit;
import
java.util.concurrent.atomic.AtomicInteger;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
public
class
SynchronizedVsLockTest {
static
final
Object mutex1 =
new
Object();
static
final
Object mutex2 =
new
Object();
static
final
Lock lock1 =
new
ReentrantLock();
static
final
Lock lock2 =
new
ReentrantLock();
static
int
counter1 =
0
;
static
int
counter2 =
0
;
static
final
AtomicInteger counter3 =
new
AtomicInteger();
static
final
AtomicInteger counter4 =
new
AtomicInteger();
public
static
final
int
LOOPS =
50
*
1000
*
1000
;
static
final
Map<integer,
double
[]=
""
> results =
new
TreeMap<integer,
double
[]=
""
>();
@Test
public
void
testSvL()
throws
InterruptedException {
testSvL1();
testSvL2();
for
(Map.Entry<integer,
double
[]=
""
> entry : results.entrySet()) {
System.out.print(
""
);
System.out.print(entry.getKey());
for
(
double
v : entry.getValue()) {
System.out.print(
""
);
System.out.printf(
"%.3f"
, v);
}
System.out.println(
""
);
}
}
static
void
testSvL1()
throws
InterruptedException {
for
(
final
int
t :
new
int
[] {
1
,
2
,
4
,
8
,
16
,
32
,
64
}) {
doTest(t,
0
,
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
0
; i < LOOPS / t; i++) {
synchronized
(mutex1) {
counter1++;
}
}
}
@Override
public
String toString() {
return
"1x synchronized {}"
;
}
});
doTest(t,
1
,
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
0
; i < LOOPS / t; i++) {
lock1.lock();
try
{
counter1++;
}
finally
{
lock1.unlock();
}
}
}
@Override
public
String toString() {
return
"1x Lock.lock()/unlock()"
;
}
});
doTest(t,
2
,
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
0
; i < LOOPS / t; i++) {
counter3.getAndIncrement();
}
}
@Override
public
String toString() {
return
"1x AtomicInteger"
;
}
});
}
}
static
void
testSvL2()
throws
InterruptedException {
for
(
final
int
t :
new
int
[] {
1
,
2
,
4
,
8
,
16
,
32
,
64
}) {
doTest(t,
3
,
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
0
; i < LOOPS / t; i++) {
synchronized
(mutex1) {
counter1++;
}
synchronized
(mutex2) {
counter2++;
}
}
}
@Override
public
String toString() {
return
"2x synchronized {}"
;
}
});
doTest(t,
4
,
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
0
; i < LOOPS / t; i++) {
lock1.lock();
try
{
counter1++;
}
finally
{
lock1.unlock();
}
lock2.lock();
try
{
counter2++;
}
finally
{
lock2.unlock();
}
}
}
@Override
public
String toString() {
return
"2x Lock.lock()/unlock()"
;
}
});
doTest(t,
5
,
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
0
; i < LOOPS / t; i++) {
counter3.getAndIncrement();
counter4.getAndIncrement();
}
}
@Override
public
String toString() {
return
"2x AtomicInteger"
;
}
});
}
}
private
static
void
doTest(
int
threads,
int
testNum, Runnable runnable)
throws
InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(threads);
long
start = System.nanoTime();
try
{
for
(
int
i =
0
; i < threads; i++)
es
.execute(runnable.getClass().getDeclaredConstructor(
int
.
class
).newInstance(threads));
}
catch
(Exception e) {
throw
new
AssertionError(e);
}
finally
{
es.shutdown();
}
es.awaitTermination(
1
, TimeUnit.MINUTES);
long
time = (System.nanoTime() - start) /
1000000
;
System.out.printf(
"%s with %d threads took %.3f seconds%n"
, runnable
.toString(), threads, time / 1e3);
double
[] times = results.get(threads);
if
(times ==
null
)
results.put(threads, times =
new
double
[
6
]);
times[testNum] = time / 1e3;
}
}
|
转载自: http://www.javasleep.com/archive/lock_synchronized.html