读写锁顾名思义分离读操作和写操作,可以有效的减少锁竞争以提高系统的性能。读写锁提升性能的地方主要在读读操作(读操作不会改变数据的一致性和完整性),而读写、写写、写读操作之间则会互斥造成阻塞。因此,读写锁应用场景适用于读操作次数大于写操作次数,读操作次数远大于写操作次数时,系统性能提升最明显。
ReadWriteLock接口定义了获取读锁和写锁两个方法,接下来对比串行的重入锁,来测试读写锁性能:
public class ReadWriteLockDemo {
/**
* 定义重入锁,对比性能
*/
private static Lock lock = new ReentrantLock();
/**
* 定义读写锁,测试读写分离操作效率
*/
private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private static ReadLock readLock = readWriteLock.readLock();
private static WriteLock writeLock = readWriteLock.writeLock();
/**
* 全局读写变量
*/
private int value;
/**
* 模拟读操作
* @param lock 使用何种锁
* @return
* @throws InterruptedException
*/
public Object handleRead(Lock lock) throws InterruptedException{
try {
lock.lock();
Thread.sleep(1000);
return value;
} finally {
lock.unlock();
}
}
/**
* 模拟写操作
* @param lock 锁
* @param index 写入值
* @throws InterruptedException
*/
public void handleWrite(Lock lock, int index) throws InterruptedException{
try {
lock.lock();
Thread.sleep(1000);
value = index;
} finally {
lock.unlock();
}
}
/**
* 创建读写两个线程实例,构建多线程模拟
* @param args
*/
public static void main(String[] args) {
final ReadWriteLockDemo demo = new ReadWriteLockDemo();
Runnable readRunnable = new Runnable() {
@Override
public void run() {
try {
int num = (int)demo.handleRead(readLock);
//int num = (int)demo.handleRead(lock);
System.out.println(num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable writeRunnable = new Runnable() {
@Override
public void run() {
try {
demo.handleWrite(writeLock, new Random().nextInt());
//demo.handleWrite(lock, new Random().nextInt());
System.out.println("write now ...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 18; i++) {
new Thread(readRunnable).start();
}
for (int i = 18; i < 20; i++) {
new Thread(writeRunnable).start();
}
}
}
性能提升主要是在于读操作时,重入锁串行读取耗时多,而改用读写锁之后读操作变为并发读,节省了时间。