ReadWriteLock维持着一对关联的锁.一个仅仅为读操作,一个仅仅为写操作.
只要没有写操作,读锁不是互斥的.然而写锁是互斥的
所有ReadWriteLock实现必须保证writeLock操作的内存同步效果对于相关的readLock而言也是一样的.
也就是说,一个线程成功获取读锁定将会看到在之前释放的写锁定所做的所有更新.
读写分离锁可以有效的帮助减少锁竞争,以提升性能。
用锁分离的机制来提升性能非常容易理解,比如线程A1,A2,A3进行写操作,B1,B2,B3进行读操作,如果使用重入锁或者内部锁,则理论上说所有读之间、读和写之间、写和写之间都是串行操作。当B1进行读取时,B2,B3则需要等待锁的释放。由于读操作并不对数据的完整性造成破坏,这种等待显然是不合理。因此,读写锁就有了发挥功能的余地。
在这种情况下,读写锁允许多个线程同时读,使得B1,B2,B3之间真正并行。但是,考虑到数据完整性,写写操作和读写操作间仍然是需要相互等待和持有锁的。总的来说,读写锁的访问约束如下:
如果在系统中,读操作次数远远大于写操作,则读写锁就可以发挥最大的功效,提升系统的性能。
书中的demo:
public class ReadWriteLockDemo {
private static Lock lock = new ReentrantLock();
private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private static Lock readLock = readWriteLock.readLock();
private static Lock writeLock = readWriteLock.writeLock();
private int value;
public Object handleRead(Lock lock) throws InterruptedException {
try {
lock.lock(); // 模拟读操作
Thread.sleep(1000); // 读操作耗时越多,读写锁的优势越明显
return value;
} finally {
lock.unlock();
}
}
public void handleWrite(Lock lock, int index) throws InterruptedException {
try {
lock.lock(); // 模拟写操作
Thread.sleep(1000);
value = index;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
final ReadWriteLockDemo demo = new ReadWriteLockDemo();
Runnable readRunnale = new Runnable() {
@Override
public void run() {
try {
demo.handleRead(readLock);
// demo.handleRead(lock);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable writeRunnale = new Runnable() {
@Override
public void run() {
try {
demo.handleWrite(writeLock,new Random().nextInt());
// demo.handleWrite(lock, new Random().nextInt());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 18; i++) {
new Thread(readRunnale).start();
}
for (int i = 18; i < 20; i++) {
new Thread(writeRunnale).start();
}
}