排他鎖:synchronized和ReentrantLock都是排他鎖,排他鎖的意思就是在這一時刻隻能有一個線程進入
讀寫鎖:ReentrantReadWriteLock同一時刻允許多個讀線程同時通路,但是寫線程通路的時候,所有的讀和寫都被阻塞,最适宜與讀多寫少的情況
由于使用者大部分的請求都是讀,是以可以認為讀寫鎖的效率比排他鎖是質的飛躍
我們使用Synchronized實作一次和讀寫鎖ReentrantReadWriteLock實作一次,來看效率對比
/**
*類說明:商品的實體類
*/
public class GoodsInfo {
private final String name;
private double totalMoney;//總銷售額
private int storeNumber;//庫存數
public GoodsInfo(String name, int totalMoney, int storeNumber) {
this.name = name;
this.totalMoney = totalMoney;
this.storeNumber = storeNumber;
}
public double getTotalMoney() {
return totalMoney;
}
public int getStoreNumber() {
return storeNumber;
}
public void changeNumber(int sellNumber){
this.totalMoney += sellNumber*25;
this.storeNumber -= sellNumber;
}
}
/**
*類說明:商品的服務的接口
*/
public interface GoodsService {
public GoodsInfo getNum();//獲得商品的資訊
public void setNum(int number);//設定商品的數量
}
/**
*類說明:讀寫鎖ReetrantReadWriteLock實作
*/
public class UseRwLock implements GoodsService {
private GoodsInfo goodsInfo;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock getLock = lock.readLock();//讀鎖
private final Lock setLock = lock.writeLock();//寫鎖
public UseRwLock(GoodsInfo goodsInfo) {
this.goodsInfo = goodsInfo;
}
@Override
public GoodsInfo getNum() {
getLock.lock();
try {
SleepTools.ms(5);
return this.goodsInfo;
}finally {
getLock.unlock();
}
}
@Override
public void setNum(int number) {
setLock.lock();
try {
SleepTools.ms(5);
goodsInfo.changeNumber(number);
}finally {
setLock.unlock();
}
}
}
/**
*類說明:用排他鎖來實作商品服務接口
*/
public class UseLock implements GoodsService {
private GoodsInfo goodsInfo;
private final Lock lock = new ReentrantLock();
public UseLock(GoodsInfo goodsInfo) {
this.goodsInfo = goodsInfo;
}
@Override
public GoodsInfo getNum() {
lock.lock();
try {
SleepTools.ms(5);
return this.goodsInfo;
}finally {
lock.unlock();
}
}
@Override
public void setNum(int number) {
lock.lock();
try {
SleepTools.ms(5);
goodsInfo.changeNumber(number);
}finally {
lock.unlock();
}
}
}
接下來我們的測試類
/**
*類說明:對商品進行業務的應用
*/
public class BusiApp {
static final int readWriteRatio = 10;//讀寫線程的比例
static final int minthreadCount = 3;//最少線程數
//讀操作
private static class GetThread implements Runnable{
private GoodsService goodsService;
public GetThread(GoodsService goodsService) {
this.goodsService = goodsService;
}
@Override
public void run() {
long start = System.currentTimeMillis();
for(int i=0;i<100;i++){//操作100次
goodsService.getNum();
}
System.out.println(Thread.currentThread().getName()+"讀取商品資料耗時:"
+(System.currentTimeMillis()-start)+"ms");
}
}
//寫操做
private static class SetThread implements Runnable{
private GoodsService goodsService;
public SetThread(GoodsService goodsService) {
this.goodsService = goodsService;
}
@Override
public void run() {
long start = System.currentTimeMillis();
Random r = new Random();
for(int i=0;i<10;i++){//操作10次
SleepTools.ms(50);
goodsService.setNum(r.nextInt(10));
}
System.out.println(Thread.currentThread().getName()
+"寫商品資料耗時:"+(System.currentTimeMillis()-start)+"ms---------");
}
}
public static void main(String[] args){
GoodsInfo goodsInfo = new GoodsInfo("Cup",100000,10000);
GoodsService goodsService =/* new UseRwLock(goodsInfo);*/new UseLock(goodsInfo);
for(int i = 0;i<minthreadCount;i++){
Thread setT = new Thread(new SetThread(goodsService));
for(int j=0;j<readWriteRatio;j++) {
Thread getT = new Thread(new GetThread(goodsService));
getT.start();
}
SleepTools.ms(100);
setT.start();
}
}
}
我們測試類可以通過注釋new UseRwLock或new UseLock來切換使用什麼方式,這裡我們試着使用排他鎖,輸入大緻如下
獲得第一個鎖時間為600多毫秒,可最後積累時間:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLzMDOwUzN0MjMyADNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
思路大家可以看代碼來了解,這裡不作詳細解釋,接下來我們試一下讀寫鎖
綜合計算下來性能差距大概20倍,如果業務資料量更多,效率可想而知