Java中各种Lock的使用
介绍几种锁的基本使用。
ReentrantLock
Java.util.concurrent.locks.*
包中有三个接口:Lock、Condition、ReadWriteLock。两个重要的锁对象:公平锁-ReentrantLock、读写锁-ReentrantReadWriteLock。
并发编程中使用Lock的目的是实现相应的同步效果。
- ReentrantLock类
- java.util.concurrent.locks.ReentrantLock类
Java多线程中,使用synchronized关键字实现线程间的同步和互斥,但ReentrantLock(实现自Lock接口)类也能得到同样的效果,同时还扩展更多功能,包括:嗅探锁定、多路分支通知等。reentrant是可重入的意思,就像Python中的threadin.RLock。可重入锁在同一个线程内获取多次不会锁定。
instance 11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package service
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Service {
private Lock lock = new ReentrantLock();
public void test() {
lock.lock();
for (int i = 1; i < 5; i++) {
System.out.println("ThreadName=" + Thread.currentThread().getName() + "num: " + i);
}
lock.unlock();
}
}
- 使用Condition实现等待/通知
关键字synchronized与wait和notify/notifyAll方法结合可以实现等待/通知模式。ReentrantLock中的newConditon函数可以创建condition锁对象。类比于Python中的threading.Condition对象。
instance 2
condition.await()调用前调用lock.lock方法获得同步监听器。对比Python中的Condition的用法。
1 | import threading |
1 | import java.util.concurrent.locks.Condition; |
Java的condition锁中没有像Python中的condition那样通过内置的acquire方法获取同步监听器,所以需要外部设置锁lock,调用unlock方法获取同步监听器。
condition | synchronized |
---|---|
await/signal/signalAll | wait/nofity/notifyAll |
一个综合例子: 生产者/消费者模型:交替打印输出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
42import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set() {
try {
lock.lock();
while (hasValue) {
System.out.println("print **");
condition.await();
}
System.out.println("print *");
hasValue = true;
condition.signal(); //wait up one thread
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get() {
try {
lock.lock();
while (hasValue) {
System.out.println("print --");
condition.await();
}
System.out.println("print -");
hasValue = false;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
- 公平锁/非公平锁
公平锁是锁分配的顺序按照线程请求锁的顺序确定。类比FIFO。非公平锁则是随机抢占。ReentrantLock类的构造器可以传入一布尔类型确定是否是公平锁。
1 | import java.util.concurrent.locks.ReentrantLock; |
ReentrantLock 中的方法
1 | import java.util.concurrent.locks.ReentrantLock; |
ReentrantReadWriteLock
读写锁表示两个锁,分别是读锁、写锁。读锁也称为共享锁;写锁称为排他锁。于是,多个读锁之间不互斥,但读锁和写锁、写锁和写锁是互斥的。在多线程下,多个线程可以同时读取数据,但只能有一个线程进行写入操作。读锁、写锁的更详细理论参考数据库原理中的读写锁。
互斥情况:
- 读读共享
- 写写互斥
- 读写互斥
instance 3
1 | import java.util.locks.ReentrantReadWriteLock; |