1.什么是读写锁
读写锁就是对共享资源既可以加读锁,也可以加写锁,而不是简单的独占锁。当没有对共享资源加写锁时,多个线程都可以申请读锁,但是只能有一个线程加写锁;当对共享资源加了写锁后,其他线程不能加读锁和写锁。写锁是独占锁,读锁是共享锁。
2.读写锁的简单实现
package lock;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReadWriteLock;
/**
* 读写锁,如果没有写锁,都可以加读锁,只能一个线程加写锁;如果有写锁,
*
*
*/
public class MyReadWriteLock implements ReadWriteLock {
/**
* 写锁标识,0-无写锁,1-申请写锁,2-有写锁
*/
private volatile int writeFlag;
private final ReadLock readLock;
private final WriteLock writeLock;
private final Sync sync = new Sync();
public MyReadWriteLock() {
this.readLock = new ReadLock();
this.writeLock = new WriteLock();
}
public boolean isWrite() {
return writeFlag > 0;
}
public int getWriteFlag() {
return writeFlag;
}
public void compareAndSetWriteFlag(int expect, int update) {
unsafe.compareAndSwapInt(this, writeFlagOffset, expect, update);
}
public Sync getSync() {
return sync;
}
class Sync extends AbstractQueuedSynchronizer {
@Override
protected int tryAcquireShared(int arg) {
int c = getState();
if (getWriteFlag() > 0 && getExclusiveOwnerThread() != Thread.currentThread()) {//正在申请写锁或者已加写锁,不能再加读锁
return -1;
}
compareAndSetState(getState(), getState() + 1);
return 1;
}
@Override
protected boolean tryReleaseShared(int arg) {
return compareAndSetState(getState(), getState() - 1);
}
@Override
protected boolean tryAcquire(int arg) {
if (getWriteFlag() > 0 || getState() > 0) {//已加写锁或读锁,不能加写锁,得等待读锁或者写锁释放
return false;
}
compareAndSetWriteFlag(getWriteFlag(), getWriteFlag() + 1);
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
@Override
protected boolean tryRelease(int arg) {
compareAndSetWriteFlag(getWriteFlag(), getWriteFlag() - 1);
setExclusiveOwnerThread(null);
return true;
}
}
/**
* 读锁
*/
class ReadLock implements java.util.concurrent.locks.Lock {
final Sync sync;
public ReadLock() {
sync = getSync();
}
@Override
public void lock() {
sync.acquireShared(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
sync.releaseShared(1);
}
@Override
public Condition newCondition() {
return null;
}
}
class WriteLock implements java.util.concurrent.locks.Lock {
final Sync sync;
public WriteLock() {
this.sync = getSync();
}
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return null;
}
}
/**
* 加读锁
*/
public java.util.concurrent.locks.Lock readLock() {
return readLock;
}
/**
* 加写锁
*/
public java.util.concurrent.locks.Lock writeLock() {
return writeLock;
}
private static final Unsafe unsafe;
private static final long writeFlagOffset;
static {
try {
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
unsafe = (Unsafe) theUnsafeInstance.get(Unsafe.class);
writeFlagOffset = unsafe.objectFieldOffset(MyReadWriteLock.class.getDeclaredField("writeFlag"));
} catch (Exception e) {
throw new Error(e);
}
}
}
3.示例
import lock.MyReadWriteLock;
/**
* 场景描述:网上图书馆里的书只能管理员进行修改,读者只能读。
* 10个读者可以同时读同一本书,但是管理员修改书的时候任何人都不能读
*/
public class TestMyReadWriteLock {
private static final MyReadWriteLock lock = new MyReadWriteLock();
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new Thread(new Reader(i+1)).start();
}
new Thread(new Manager("管理员")).start();
}
/**
* 管理员线程
*/
static class Manager implements Runnable {
private String name;
public Manager(String name) {
this.name = name;
}
@Override
public void run() {
Thread.currentThread().setName(name);
while (true) {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName() +"加写锁成功,可以进行写操作");
System.out.println(Thread.currentThread().getName() +"正在进行写操作。。。。。");
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() +"写操作异常");
lock.writeLock().unlock();
}
System.out.println(Thread.currentThread().getName() +"写操作完毕,释放写锁");
lock.writeLock().unlock();
//隔一段时间再进行写操作
try {
Thread.sleep(30*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 读者
*/
static class Reader implements Runnable {
/**
* 隔一段时间再去读书
*/
private long readTime;
public Reader(long readTime) {
this.readTime = readTime;
}
@Override
public void run() {
while (true) {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + "加读锁成功,可以进行读操作");
System.out.println(Thread.currentThread().getName() +"正在进行读操作。。。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName() +"读操作异常,释放本身持有的读锁");
lock.readLock().unlock();
}
System.out.println(Thread.currentThread().getName() +"读操作完毕,释放本身持有的读锁");
lock.readLock().unlock();
//隔一段时间再进行写操作
try {
Thread.sleep(readTime * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}