维护一对关联锁,一个只能用来读操作,一个只能用来写操作;
读锁可以由多个读线程共同持有(共享锁),写锁是排他的(独享锁)。
同一时间,两把锁不能被不同线程持有
适合读取操作多于写入操作的场景,改进互斥锁的性能,比如:集合的并发线程安全性改造、缓存组件。
为什么读的时候还需要加锁?
当写的操作为需要保证原子性的多步操作时,此时如果只是在写上加锁而未在读上加锁,就可能会造成原子性问题,即当写执行到一半的时候,另外一个线程执行了读操作,从而使得读到的数据时不准确的,产生了数据分裂。
指的是写锁降级为读锁。持有写锁的同时,在获取读锁,锁喉释放写锁的过程。写锁时线程独占,读锁是共享的,所以写到读是降级(读到写为升级,是不能实现的)。
package com.hzw.subject1.lock;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyLockHashMap {
private final Map<String, Object> m = new HashMap<>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public Object get(String key) {
r.lock();
try {
return m.get(key);
} finally {
r.unlock();
}
}
public Object[] allKeys() {
r.lock();
try {
return m.keySet().toArray();
} finally {
r.unlock();
}
}
public Object put(String key, Object obj) {
w.lock();
try {
return m.put(key, obj);
} finally {
w.unlock();
}
}
public void clear() {
w.lock();
try {
m.clear();
} finally {
w.unlock();
}
}
}
package com.hzw.subject1.lock;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class MyLockCache {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(UserInfoCache.get("insist"));
}
}).start();
}
}
}
class UserInfoCache {
private static volatile boolean cacheValid;
private static final ReadWriteLock rwl = new ReentrantReadWriteLock();
static Object get(String dataKey) {
Object data = null;
//读取数据,加读锁
rwl.readLock().lock();
try {
if (cacheValid) {
data = Redis.data.get(dataKey);
} else {
//通过加锁的方式去访问DB,加写锁
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
if (!cacheValid) {
data = DataBase.queryUserInfo();
Redis.data.put(dataKey, data);
cacheValid = true;
} else {
data = Redis.data.get(dataKey);
}
} finally {
//锁降级
rwl.readLock().lock();
rwl.writeLock().unlock();
}
}
return data;
} finally {
rwl.readLock().unlock();
}
}
}
class DataBase {
static String queryUserInfo() {
System.out.println("查询数据库。。。");
return "name:insist,age:18,gender:true,";
}
}
class Redis {
static Map<String, Object> data = new HashMap<>();
}
package com.hzw.subject1.lock.mylock;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.*;
public class MyReadWriteLock implements ReadWriteLock {
private AtomicInteger rCount = new AtomicInteger();
private AtomicInteger wCount = new AtomicInteger();
/**
* 独占锁的拥有者
*/
private AtomicReference<Thread> owner = new AtomicReference<>();
/**
* 等待队列
*/
private LinkedBlockingQueue<Node> waiters = new LinkedBlockingQueue<>();
static class Node{
//独占锁type
static final int MONOPOLY = 0;
//共享锁type
static final int SHARE = 1;
/**
* 约定必须为一下选项:
* MONOPOLY 为想获取独占锁的线程
* SHARE为想获取共享锁的线程
*/
int type;
Thread thread;
int arg;
public Node(Thread thread, int type, int arg){
this.thread = thread;
this.type = type;
this.arg = arg;
}
public static Node createMonopoly(Thread thread) {
return new Node(thread, MONOPOLY, 1);
}
public static Node createShare(Thread thread) {
return new Node(thread, SHARE, 1);
}
}
@Override
public Lock readLock() {
return new Lock() {
@Override
public void lock() {
//尝试抢锁
if (!tryLock()) {
Node current = Node.createMonopoly(Thread.currentThread());
//抢锁失败,加入等待队列
waiters.offer(current);
//自旋
for (; ; ) {
Node head = waiters.peek();
//如果唤醒的不是队列头,在判定为伪唤醒,让其重新进入park状态
if (null != head && head.thread == Thread.currentThread() && tryLock()) {
//唤醒的线程抢到锁以后移除等待队列
waiters.poll();
//如果下一个线程依旧是读线程,继续唤醒下一个线程
Node next = waiters.peek();
if (null != next && next.type == Node.SHARE) {
LockSupport.unpark(next.thread);
}
return;
}
LockSupport.park();
}
}
}
@Override
public boolean tryLock() {
int wc = wCount.get();
if (wc == 0)
return rCount.incrementAndGet() > 0;
if (owner.get() == Thread.currentThread())
return rCount.incrementAndGet() > 0;
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
//当前线程中断状态为true则抛出异常
if (Thread.interrupted())
throw new InterruptedException();
//尝试抢锁
if (tryLock())
return true;
//如果等待时间<=0则直接抢锁失败
if (time <= 0)
return false;
//将time转换为纳秒
long nanos = unit.toNanos(time);
//抢锁的最后期限
long deadline = nanos + System.nanoTime();
for (; ; ) {
if (tryLock())
return true;
if (System.nanoTime() - deadline > 0L)
return false;
}
}
@Override
public void unlock() {
//尝试解锁
if (tryUnlock()) {
//解锁成功,唤醒等待队列头部的线程
Node head = waiters.peek();
if (null != head) {
LockSupport.unpark(head.thread);
}
}
}
/**
* 尝试解除共享锁
* @return 是否解除
*/
private boolean tryUnlock() {
for (; ; ) {
int rc = rCount.get();
int nrc = rc - 1;
if (rCount.compareAndSet(rc, nrc))
return nrc == 0;
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
//判断线程中断状态
if (Thread.interrupted())
throw new InterruptedException();
//尝试抢锁
if (!tryLock()) {
Node current = Node.createMonopoly(Thread.currentThread());
//抢锁失败,加入等待队列
waiters.offer(current);
//自旋
for (; ; ) {
Node head = waiters.peek();
//如果唤醒的不是队列头,在判定为伪唤醒,让其重新进入park状态
if (null != head && head.thread == Thread.currentThread() && tryLock()) {
//唤醒的线程抢到锁以后移除等待队列
waiters.poll();
//如果下一个线程依旧是读线程,继续唤醒下一个线程
Node next = waiters.peek();
if (null != next && next.type == Node.SHARE) {
LockSupport.unpark(next.thread);
}
return;
}
//判断线程中断状态
if (Thread.interrupted())
throw new InterruptedException();
LockSupport.park();
}
}
}
@Override
public Condition newCondition() {
return null;
}
};
}
@Override
public Lock writeLock() {
return new Lock() {
@Override
public void lock() {
//尝试抢锁
if (!tryLock()) {
Node current = Node.createMonopoly(Thread.currentThread());
//抢锁失败,加入等待队列
waiters.offer(current);
//自旋
for (; ; ) {
Node head = waiters.peek();
//如果唤醒的不是队列头,在判定为伪唤醒,让其重新进入park状态
if (current == head && tryLock()) {
//唤醒的线程抢到锁以后移除等待队列
waiters.poll();
return;
}
LockSupport.park();
}
}
}
@Override
public boolean tryLock() {
int rc = rCount.get();
int wc = wCount.get();
//判断wCount是否为0,若wCount != 0 则说明锁已经被占用
if (wc == 0) {
if (rc != 0)
return false;
//通过CAS(0, 1)进行抢锁
if (wCount.compareAndSet(wc, 1)) {
//将owner设为当前线程的引用
owner.set(Thread.currentThread());
return true;
}
//判断当前占用锁的线程是否为当前线程
} else if(owner.get() == Thread.currentThread()){
//锁重入,count++
wCount.getAndIncrement();
return true;
}
//锁已被占用,且不是自己或抢锁失败
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
//当前线程中断状态为true则抛出异常
if (Thread.interrupted())
throw new InterruptedException();
//尝试抢锁
if (tryLock())
return true;
//如果等待时间<=0则直接抢锁失败
if (time <= 0)
return false;
//将time转换为纳秒
long nanos = unit.toNanos(time);
//抢锁的最后期限
long deadline = nanos + System.nanoTime();
for (; ; ) {
if (tryLock())
return true;
if (System.nanoTime() - deadline > 0L)
return false;
}
}
@Override
public void unlock() {
//尝试解锁
if (tryUnlock()) {
//解锁成功,唤醒等待队列头部的线程
Node head = waiters.peek();
if (null != head) {
LockSupport.unpark(head.thread);
}
}
}
private boolean tryUnlock() {
//判断是否是当前线程拿到的锁,如果不是,抛出异常
if (owner.get() != Thread.currentThread())
throw new IllegalMonitorStateException();
//将count减1
int c = wCount.get() -1;
//判断count是否为0,如果为0,则当前线程的锁全部解完,将owner置空
if (c != 0)
return false;
owner.set(null);
wCount.set(c);
return true;
}
@Override
public void lockInterruptibly() throws InterruptedException {
//判断线程中断状态
if (Thread.interrupted())
throw new InterruptedException();
//尝试抢锁
if (!tryLock()) {
Node current = Node.createMonopoly(Thread.currentThread());
//抢锁失败,加入等待队列
waiters.offer(current);
//自旋
for (; ; ) {
Node head = waiters.peek();
//如果唤醒的不是队列头,在判定为伪唤醒,让其重新进入park状态
if (current == head && tryLock()) {
//唤醒的线程抢到锁以后移除等待队列
waiters.poll();
return;
}
//判断线程中断状态
if (Thread.interrupted())
throw new InterruptedException();
LockSupport.park();
}
}
}
@Override
public Condition newCondition() {
return null;
}
};
}
}