在Java多线程中,可以使用synchronized关键字来实现线程之间的同步互斥,但在JDK1.5后新增了ReetrantLock类也能达到同样的效果,并且在扩展功能上也更加强大。
1.ReentrantLock类的使用
1.1 简单使用 ReentrantLock
1 | import java.util.concurrent.locks.ReentrantLock; |
最后的结果是 20000000;如果去掉锁,那么输出结果是一个小于20000000的不确定的数。
1.2 使用Conditon实现等待/通知
1 | package com.jalja.org.base.Thread; |
需要注意,在调用condition.await()和condition.signal()之前必须先调用lock.lock()代码,获得同步监视器,也就是先要获得锁。
1.3 使用多个Condition实现通知部分线程
新建MyService.java: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
125package service;
importjava.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
public class MyService {
privateLock lock = new ReentrantLock();
publicCondition conditionA = lock.newCondition();
publicCondition conditionB = lock.newCondition();
publicvoid awaitA() {
try{
lock.lock();
System.out.println("beginawaitA时间为" +System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionA.await();
System.out.println(" end awaitA时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
publicvoid awaitB() {
try{
lock.lock();
System.out.println("beginawaitB时间为" +System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionB.await();
System.out.println(" end awaitB时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
publicvoid signalAll_A() {
try{
lock.lock();
System.out.println(" signalAll_A时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionA.signalAll();
}finally {
lock.unlock();
}
}
publicvoid signalAll_B() {
try{
lock.lock();
System.out.println(" signalAll_B时间为" + System.currentTimeMillis()
+" ThreadName=" + Thread.currentThread().getName());
conditionB.signalAll();
}finally {
lock.unlock();
}
}
新建ThreadA.java :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
35package extthread;
import service.MyService;
public class ThreadA extends Thread {
privateMyService service;
publicThreadA(MyService service) {
super();
this.service= service;
}
@Override
publicvoid run() {
service.awaitA();
}
}
新建ThreadB.java :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
35package extthread;
import service.MyService;
public class ThreadB extends Thread {
privateMyService service;
publicThreadB(MyService service) {
super();
this.service= service;
}
@Override
publicvoid run() {
service.awaitB();
}
}
新建Run.java :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
49package test;
import service.MyService;
import extthread.ThreadA;
import extthread.ThreadB;
public class Run {
publicstatic void main(String[] args) throws InterruptedException {
MyServiceservice = new MyService();
ThreadAa = new ThreadA(service);
a.setName("A");
a.start();
ThreadBb = new ThreadB(service);
b.setName("B");
b.start();
Thread.sleep(3000);
service.signalAll_A();
}
}
运行结果,只有线程A被唤醒了。
1.4 公平锁和非公平锁
锁Lock分为公平锁和非公平锁。公平锁表示线程获取锁的顺便是按照线程加锁的顺序来分配的,即先来先得,先进先出的顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的。
公平锁的顺序是大体如此,并不是100%。
在默认情况下,ReentrantLock类使用的是非公平锁。
1.5 使用Conditon可实现顺序执行
2.ReentrantReadWriteLock类的使用
ReentrantReadWriteLock类表示有两种锁,一个是读操作相关的锁,也称共享锁;另一个是写操作相关的锁,也叫排他锁。写锁与写锁互斥,写锁与读锁互斥,读锁与读锁不互斥。
读锁是长这样的:1
2
3
4
5
6.....
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
.....
lock.readLock().lock()
.....
lock.readLock().unlock()
写锁长这样:1
2
3
4
5
6.....
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
.....
lock.writeLock().lock()
.....
lock.writeLock().unlock()
使用方法和普通的Lock类似,只要记得写锁与写锁互斥,写锁与读锁互斥,读锁与读锁不互斥。