Lock接口
主要方法:
Lock與 synchronized的比較
synchronized 代碼簡潔(關鍵字,是屬於語言層面實現同步)
Lock:獲取鎖可以被中斷,超時獲取鎖,嘗試獲取鎖,讀多寫少用讀寫鎖(是JDK提供的一個接口,來實現同步)
可重入鎖ReentrantLock
public class LockDemo {
static Lock lock = new ReentrantLock();
static int count;
public void increase(int num){
lock.lock();//獲取鎖
try{
count = count + num;
}finally {
lock.unlock();
}
}
public synchronized void increase_syn(int num){
count = count + num;
}
//synchronized方法調用另一個synchronized方法,可重入鎖,釋放鎖時,一個一個釋放
public synchronized void syn2(int num){
increase_syn(num);
}
}
公平鎖和飛公平鎖
如果在時間上,先對鎖進行獲取的請求,一定先被滿足,這個鎖就是公平的,不滿足,就是非公平的
非公平的效率一般來講更高
ReentrantLock默認非公平鎖
ReadWriteLock
實現類:ReentrantReadWriteLock
同一時刻允許多個讀線程同時訪問,但是寫線程訪問的時候,所有的讀和寫都被阻塞
示例:ReentrantReadWriteLock 與 synchronized的對比
public class GoodServiceLock implements GoodService{
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Lock readLock = lock.readLock();
private Lock writeLock = lock.writeLock();
private GoodInfo goodInfo;
public GoodServiceLock(GoodInfo goodInfo){
this.goodInfo = goodInfo;
}
@Override
public GoodInfo getNum() {
readLock.lock();
try {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return goodInfo;
}finally {
readLock.unlock();
}
}
@Override
public void setNum(int number) {
writeLock.lock();
try {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodInfo.changeNumber(number);
}finally {
writeLock.unlock();
}
}
}
public class GoodServiceSyn implements GoodService{
private GoodInfo goodInfo;
public GoodServiceSyn(GoodInfo goodInfo){
this.goodInfo = goodInfo;
}
@Override
public synchronized GoodInfo getNum() {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.goodInfo;
}
@Override
public synchronized void setNum(int number) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodInfo.changeNumber(number);
}
}
public class GoodTest {
private static int writeNum = 2;
private static int readNum = 5;
static class ReadGoodThread extends Thread {
private GoodService goodService;
public ReadGoodThread(GoodService goodService) {
this.goodService = goodService;
}
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {//操作100次
goodService.getNum();
}
System.out.println(Thread.currentThread().getName() + "讀取商品數據耗時:"
+ (System.currentTimeMillis() - start) + "ms");
}
}
static class WriteGoodThread extends Thread {
private GoodService goodService;
public WriteGoodThread(GoodService goodService) {
this.goodService = goodService;
}
@Override
public void run() {
long start = System.currentTimeMillis();
Random r = new Random();
for (int i = 0; i < 10; i++) {//操作10次
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
goodService.setNum(r.nextInt(10));
}
System.out.println(Thread.currentThread().getName()
+ "寫商品數據耗時:" + (System.currentTimeMillis() - start) + "ms---------");
}
}
public static void main(String[] args) {
GoodInfo goodInfo = new GoodInfo(100000, 10000);
GoodService goodsService = new GoodServiceSyn(goodInfo);
// GoodService goodsService = new GoodServiceLock(goodInfo);
for (int i = 0; i < writeNum; i++) {
Thread setT = new Thread(new WriteGoodThread(goodsService));
for (int j = 0; j < readNum; j++) {
Thread getT = new Thread(new ReadGoodThread(goodsService));
getT.start();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
setT.start();
}
}
}
運行結果:
synchronized:
Thread-23讀取商品數據耗時:3112ms
Thread-7讀取商品數據耗時:3655ms
Thread-19讀取商品數據耗時:3749ms
Thread-9讀取商品數據耗時:4055ms
Thread-21讀取商品數據耗時:4033ms
Thread-11讀取商品數據耗時:4195ms
Thread-15讀取商品數據耗時:4330ms
Thread-17讀取商品數據耗時:4820ms
Thread-1寫商品數據耗時:4864ms---------
Thread-5讀取商品數據耗時:5116ms
Thread-3讀取商品數據耗時:5133ms
Thread-13寫商品數據耗時:4991ms---------
ReentrantReadWriteLock :
Thread-5讀取商品數據耗時:589ms
Thread-3讀取商品數據耗時:595ms
Thread-11讀取商品數據耗時:594ms
Thread-9讀取商品數據耗時:608ms
Thread-7讀取商品數據耗時:614ms
Thread-1寫商品數據耗時:605ms---------
Thread-21讀取商品數據耗時:614ms
Thread-19讀取商品數據耗時:619ms
Thread-15讀取商品數據耗時:641ms
Thread-23讀取商品數據耗時:639ms
Thread-17讀取商品數據耗時:649ms
Thread-13寫商品數據耗時:589ms---------
在讀多寫少的場景下,可以看出ReentrantReadWriteLock比synchronized的效率高出很多。
Condition
用Lock與Condition實現消息通知(類似與Obejct的wait、notify、notifyAll,但比這個更優,不會出現信號丟失的現象,一個Lock可以創建多個Condition,根據Condition的不同,分別進行await,signal、signalAll)
public class ConditionDemo {
static String CITY = "xianyang";
static Lock lock = new ReentrantLock();
static Condition siteCondition = lock.newCondition();
static Condition kmCondition = lock.newCondition();
private String site;
private int km;
public ConditionDemo(String site, int km) {
this.site = site;
this.km = km;
}
/* 變化公里數,然後通知處於wait狀態並需要處理公里數的線程進行業務處理*/
public void changeKm(){
lock.lock();
try {
this.km = 101;
kmCondition.signal();
}finally {
lock.unlock();
}
}
/* 變化地點,然後通知處於wait狀態並需要處理地點的線程進行業務處理*/
public void changeSite(){
lock.lock();
try {
this.site = "BeiJing";
siteCondition.signal();
}finally {
lock.unlock();
}
}
/*當快遞的里程數大於100時更新數據庫*/
public void waitKm(){
lock.lock();
try {
while(this.km<=100) {
try {
kmCondition.await();
System.out.println("check km thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the Km is "+this.km+",I will change db");
}
/*當快遞到達目的地時通知用戶*/
public void waitSite(){
lock.lock();
try {
while(CITY.equals(this.site)) {
try {
siteCondition.await();
System.out.println("check site thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the site is "+this.site+",I will call user");
}
}
運行結果:
check km thread[11] is be notifed.
the Km is 101,I will change db
check site thread[15] is be notifed.
the site is BeiJing,I will call user
check site thread[16] is be notifed.
the site is BeiJing,I will call user
check km thread[12] is be notifed.
the Km is 101,I will change db
根據結果可知,Condition可以單獨喚醒某一個或一類的線程。