前文
什么是 ReadWriteLock ?
ReadWriteLock 是 java.util.concurrent.locks 包下的一个接口,该接口允许一次读取多个线程,但一次只能写入一个线程
- 读锁:如果没有线程锁定 ReadWriteLock 进行写入,则多线程可以访问读锁
- 写锁:如果没有线程正在读或写,那么一个线程可以访问写锁
ReadWriteLock 定义
public interface ReadWriteLock
锁方法
以下是 Lock 类中可用的重要方法列表
方法 | 描述 |
---|---|
public Lock readLock() | 返回用于读的锁 |
public Lock writeLock() | 返回用于写的锁 |
举例一(使用读写锁)
以下TestThread程序演示了ReadWriteLock接口的这些方法。这里我们使用readlock()获取读锁定和writeLock()来获取写锁定
package com.java.springtest.testdemo;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author Woo_home
* @create by 2020/2/2
*/
public class TestThread {
// 开启公平锁
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
// 定义消息属性
private static String message = "";
// 定义读锁
static class Reader implements Runnable {
@Override
public void run() {
if (lock.isWriteLocked()) {
System.out.println("Write Lock Present");
}
lock.readLock().lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName() + " Time Taken " + (duration / 1000) + " seconds");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + ": " + message);
lock.readLock().unlock();
}
}
}
// 定义写锁 WriterA
static class WriterA implements Runnable {
@Override
public void run() {
lock.writeLock().lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName() + " Time Taken " + (duration / 1000) + " second");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
message = message.concat("a");
lock.writeLock().unlock();
}
}
}
// 定义写锁 WriterB
static class WriterB implements Runnable {
@Override
public void run() {
lock.writeLock().lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName() + " Time Taken " + (duration / 1000) + " second");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
message = message.concat("b");
lock.writeLock().unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
// 启动线程
Thread thread1 = new Thread(new WriterA());
thread1.setName("Writer A");
Thread thread2 = new Thread(new WriterB());
thread2.setName("Writer B");
Thread thread3 = new Thread(new Reader());
thread3.setName("Reader");
thread1.start();
thread2.start();
thread3.start();
// 线程强制执行
thread1.join();
thread2.join();
thread3.join();
}
}
输出:
举例二(使用读写锁)
定义一个资源类(未加读写锁前)
class MyCache {
private volatile Map<String,Object> map = new HashMap<>();
public void put(String key,Object value) {
System.out.println(Thread.currentThread().getName() + " 写入数据" + key);
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key,value);
System.out.println(Thread.currentThread().getName() + " 写入完成");
}
public void get(String key) {
System.out.println(Thread.currentThread().getName() + " 读取数据");
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName() + " 读取完成" + result);
}
}
测试类:
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt+"",tempInt+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt+"");
},String.valueOf(i)).start();
}
}
}
输出:
可以发现,当一个线程写入的时候,另外的线程也在写入,导致其它线程会读取不到数据,正确的例子应该是写入之后会有个写入完成再读取数据的
资源类(加读写锁后)
class MyCache {
private volatile Map<String,Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key,Object value) {
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 写入数据" + key);
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key,value);
System.out.println(Thread.currentThread().getName() + " 写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
public void get(String key) {
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 读取数据");
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object result = map.get(key);
System.out.println(Thread.currentThread().getName() + " 读取完成" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
测试类
package juc;
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt+"",tempInt+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt+"");
},String.valueOf(i)).start();
}
}
}
输出: