使用独占锁最大的特点在与其只允许一个线程进行操作,这样进行数据更新的时候可以保证操作的完整性,但是在进行数据读取时,独占锁就会造成严重的性能问题。为了解决高并发下快速访问与安全修改,JUC提供了ReentrantReadWriteLock读/写锁,即在读取的时候上读锁,在写入的时候上写锁,这两种锁是互斥的,有JVM进行控制。
在ReentrantReadWriteLock中读锁属于共享锁,而写锁只允许一个线程进行操作,所以在使用时就需要通过不同的方式获取锁。
1、使用读/写锁实现银行账户的并发写入与并发读取的例子:
package com.mydemo;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class JUCDemo {
public static void main(String[] args) {
// 实例化账户
Account account = new Account("张三", 0.0);
double moneyData[] = new double[]{100.00, 500.00, 800.00, 5000.00, 10000.00};
// 5个写入线程
for(int i = 0; i < 5; i++){
new Thread(
()->{
for(int j = 0; j < moneyData.length; j++){
// 存放金额
account.saveMoney(moneyData[j]);
}
}, "写入线程:"
).start();
}
// 5个读取线程
for(int i = 0; i < 5; i++){
new Thread(
()->{
// while (true){
// // 获取数据
// System.err.println(account.toString());
// }
for(int j = 0; j < 15; j++){
System.err.println(account.toString());
}
}, "读取线程:"
).start();
}
}
}
// 银行账户
class Account{
private String name; // 账户名称
private double asset; // 账户资产
// 读/写锁
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
/**
* 双参构造函数---设置账户信息
* @param name
* @param asset
*/
public Account(String name, double asset) {
this.name = name;
this.asset = asset;
}
/**
* 资产追加
* @param money
*/
public void saveMoney(double money){
// 获取写锁(独占锁)
this.readWriteLock.writeLock().lock();
try {
this.asset += money; // 资产修改
TimeUnit.SECONDS.sleep(2); // 模拟延迟
System.out.println("【" + Thread.currentThread().getName() +
"】修改银行资产数据,修改金额:“" + money +
"”,当前资产:" + this.asset);
} catch (Exception e) {
e.printStackTrace();
}finally {
// 释放写锁
this.readWriteLock.writeLock().unlock();
}
}
public String toString() {
try {
// 数据读取
this.readWriteLock.readLock().lock();
TimeUnit.SECONDS.sleep(1); // 模拟延迟
return "【账户信息:("+ Thread.currentThread().getName() +
")】账户名称:" + this.name +
"、银行资产" + this.asset;
} catch (Exception e) {
// e.printStackTrace();
return null;
}finally {
// 释放读锁
this.readWriteLock.readLock().unlock();
}
}
}