ReentrantLock无论是“写/写”线程、“读/读”线程、“读/写”线程之间的工作都是互斥,同一 时间只有一个线程能进入同步区域。然而大多实际场景是“读/读”线程间并不存在互斥关系,只有"读/写"线程或"写/写"线程间的操作需要互斥的。
ReentrantReadWriteLock特性:
一个资源可以被多个读操作同时访问,而只能对一个写操作访问,但读和写两者不能同时进行。
从而提高读操作的吞吐量。
使用场景:对于读多写少的场景使用ReentrantReadWriteLock 性能会比ReentrantLock高出不少。
在多线程读时互不影响,不像ReentrantLock即使是多线程读也需要每个线程获取锁。不过任何一个线程在写的时候就和ReentrantLock类似,其他线程无论读还是写都必须获取锁。
需要注意的是同一个线程可以拥有 writeLock 与 readLock (但必须先获取 writeLock 再获取 readLock, 反过来进行获取会导致死锁)
默认构造方法为 非公平模式 ,开发者也可以通过指定构造方法传参数true设置为 公平模式。
读锁的条件直接调用ReentrantReadWriteLock的 newCondition 会直接exception public Condition newCondition() {
throw new UnsupportedOperationException();
}
package com.lock;
import org.apache.log4j.Logger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 读写锁
*/
public class LockTest6 {
static Logger log = Logger.getLogger(LockTest6.class);
static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
//读锁
static Lock r = rwl.readLock();
//写锁
static Lock w = rwl.writeLock();
public static void main(String[] args) throws InterruptedException {
//读
new Thread("读线程1 "){
public void run(){
log.debug("read1 获取 锁");
r.lock();
try {
for (int i = 0; i < 10; i++) {
m1(i);
}
}finally {
r.unlock();
}
}
}.start();
//写
new Thread("写线程--"){
public void run(){
log.debug("write 获取 锁");
w.lock();
try {
for (int i = 0; i < 20; i++) {
m1(i);
}
}finally {
w.unlock();
}
}
}.start();
//读
new Thread("读线程2"){
public void run(){
log.debug("read2 获取 锁");
r.lock();
try {
for (int i = 0; i < 20; i++) {
m1(i);
}
}finally {
r.unlock();
}
}
}.start();
}
public static void m1(int i){
log.debug(Thread.currentThread().getName()+"执行任务 "+i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1:两个读线程可以并发访问,而写线程只能独自访问(独占)
2:读写支持重入但是只支持降级不止升级