简介
1.ReentrantReadWriteLock分为读锁和写锁.
2.读锁也称为共享锁,进行读相关操作,多个线程都可获取该锁.
3.写锁也称为互斥锁,进行写相关操作,同一时刻只允许一个线程获取该锁.
读读共享
示例读读共享代码:
/**
* TODO
* 类ReentrantReadWriteLock的使用:读读共享.
*
* @author 86182
* @version V1.0
* @since 2020-08-31 16:36
*/
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read() {
try {
try {
lock.readLock().lock();
System.out.println("获得读锁:" + Thread.currentThread().getName() + ":" + System.currentTimeMillis());
Thread.sleep(3000);
} finally {
lock.readLock().unlock();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
定义线程A:
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.read();
}
}
定义线程B
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.read();
}
}
测试类:
public class Test {
public static void main(String[] args) {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadB.start();
}
}
测试结果:
从结果得知两个线程是同一时刻进入read()方法.
写写互斥
代码示例:
/**
* TODO
* 类ReentrantReadWriteLock的使用:写写互斥.
*
* @author 86182
* @version V1.0
* @since 2020-08-31 16:36
*/
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read() {
try {
try {
lock.writeLock().lock();
System.out.println("获得写锁:" + Thread.currentThread().getName() + " " + System.currentTimeMillis());
Thread.sleep(3000);
} finally {
lock.writeLock().unlock();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
定义线程和测试类和读读共享一致.
测试结果:
由结果得知,当一个线程获取写锁,其他线程将会阻塞,直到该锁被释放,其他线程才能获取锁.
读写互斥
读写互斥代码示例:
/**
* TODO
* 类ReentrantReadWriteLock的使用:读写互斥.
*
* @author 86182
* @version V1.0
* @since 2020-08-31 16:36
*/
public class Service {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read() {
try {
try {
lock.readLock().lock();
System.out.println("获得读锁:" + Thread.currentThread().getName() + " " + System.currentTimeMillis());
Thread.sleep(3000);
} finally {
lock.readLock().unlock();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void write() {
try {
try {
lock.writeLock().lock();
System.out.println("获得写锁:" + Thread.currentThread().getName() + " " + System.currentTimeMillis());
Thread.sleep(3000);
} finally {
lock.writeLock().unlock();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
线程A,获取读锁.
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.read();
}
}
线程B,获取写锁.
public class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.write();
}
}
测试类:
public class Test {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
threadA.start();
Thread.sleep(1000);
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadB.start();
}
}
测试结果:
可以看到,当一个线程获取读锁操作时,其他线程获取写锁进行操作将进行阻塞,直到读操作释放锁.其他线程才能获取写锁.
简单深入了解:
1.从源码可以看出,ReentrantLock,ReentrantReadWriteLock里面有个内部类都继承了AbstractQueuedSynchronizer抽象类.
2.AbstractQueuedSynchronizer类是并发的基础框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。 以原子方式更新int使用方法操纵值getState() , setState(int)和compareAndSetState(int, int)被跟踪相对于同步。我们也可以用此类构建自定义的共享锁和独占锁.具体可自己查看源码.
3.许多并发容器的实现都是继承了该抽象类,如Semaphore,CountDownLatch.