排他锁:
- 同一时刻只允许一个线程访问
读写锁:
- 同一时刻允许多个读线程同时访问,但是写线程访问的时候,所有的读、写都被会被阻塞,适用于读多写少的场景。
- ReadWriteLock接口和读写锁ReentrantReadWriteLock
读写锁的实现
public class RwLockImpl implements GoodsService{
private Goods goods;
public RwLockImpl(Goods goods){
this.goods = goods;
}
private final ReadWriteLock lock = new ReentrantReadWriteLock();
//读锁
private final Lock readLock = lock.readLock();
//写锁
private final Lock writeLock = lock.writeLock();
//读操作
@Override
public int getGoodsNum() {
readLock.lock();
try {
ThreadUtils.sleep(5);
return this.goods.getCount();
}finally{
readLock.unlock();
}
}
//写操作
@Override
public void setGoodsSale(int num) {
writeLock.lock();
try{
ThreadUtils.sleep(5);
this.goods.changeInfo(num);
}finally{
writeLock.unlock();
}
}
}
Synchronized实现
public class SyncImpl implements GoodsService{
private Goods goods;
public SyncImpl(Goods goods){
this.goods = goods;
}
@Override
public synchronized int getGoodsNum() {
ThreadUtils.sleep(5);
return goods.getCount();
}
@Override
public synchronized void setGoodsSale(int num) {
ThreadUtils.sleep(5);
goods.changeInfo(num);
}
性能对比
项目启动3个写线程,每个线程对数据做10次修改。启动3*10个读线程,每个线程读取数据100次,分别用 ReadWriteLock 和 Synchronized 加以实现,对比下效率。
/**
* 排他锁:
* 1、同一时刻只允许一个线程访问
*
* 读写锁:
* 1、同一时刻允许多个读线程同时访问,但是写线程访问的时候,所有的读、写都被会被阻塞,适用于读多写少的场景。
* 2、ReadWriteLock接口和读写锁ReentrantReadWriteLock
*/
public class ReadWriteLockDemo {
static final int ReadThreadNum = 10;
static final int WriteThreadNum = 3;
public static void main(String[] args) {
Goods goodsInfo = new Goods("Cup",100000,10000);
//读写锁
// GoodsService goodsService = new RwLockImpl(goodsInfo);
//Synchronized锁
GoodsService goodsService = new SyncImpl(goodsInfo);
for(int i = 0;i<WriteThreadNum;i++){
Thread setT = new Thread(new WriteThead(goodsService));
for(int j=0;j<ReadThreadNum;j++) {
Thread getT = new Thread(new ReadThead(goodsService));
getT.start();
}
ThreadUtils.sleep(5);
setT.start();
}
}
/**
* 读线程
*/
public static class ReadThead implements Runnable{
public GoodsService service;
public ReadThead(GoodsService service){
this.service = service;
}
@Override
public void run() {
long start = System.currentTimeMillis();
for(int i=0;i<100;i++){
service.getGoodsNum();
ThreadUtils.sleep(5);
}
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" - "+"【读取】商品信息100次耗时"+(end-start)+"ms");
}
}
/**
* 写线程
*/
public static class WriteThead implements Runnable{
public GoodsService service;
public WriteThead(GoodsService service){
this.service = service;
}
@Override
public void run() {
long start = System.currentTimeMillis();
for(int i=0;i<10;i++){
ThreadUtils.sleep(5);
service.setGoodsSale(50);
}
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" - "+"【修改】商品信息100次耗时"+(end-start)+"ms");
}
}
}
运行结果
对比发现,当读线程远大于写线程时,ReadWriteLock的效率远大于Synchronized。