Lock鎖
在 jdk1.5 之後,併發包中新增了 Lock 接口(以及相關實現類)用來實現鎖功能,Lock 接口提供了與 synchronized 關鍵字類似的同步功能,但需要在使用時手動獲取鎖和釋放鎖,且在使用上比synchronized更加靈活。
1、使用ReentrantLock實現同步
案例:
package com.yxl.demo.ThreadTest;
public class test5 {
public static void main(String[] args) {
TestDemo thread = new TestDemo();
Thread t1 = new Thread(thread,"窗口一");
Thread t2 = new Thread(thread,"窗口二");
t1.start();
t2.start();
}
}
class TestDemo implements Runnable{
//共享的火車票變量
private int count = 100;
//重寫run方法
@Override
public void run() {
while (count > 0){
try {
//休眠一下 方便出現併發問題
Thread.sleep(50);
}catch (Exception e){
e.getMessage();
}
sale();
}
}
//賣票
public void sale(){
if(count > 0){
System.out.println(Thread.currentThread().getName() +"出售 :" +(100 - count + 1));
count--;
}
}
}
運行結果如下:會發現出現賣重複票的問題
除了 內置鎖(Synchronized)解決方案,我們可以使用 Lock鎖解決
synchronized的缺陷
synchronized是Java中的一個關鍵字。
我們知道如果一段代碼被synchronized修飾了,當一個線程獲取了對應的鎖,並執行該代碼塊的時候,其他的線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這裏獲鎖的線程釋放鎖有兩種情況:
-
獲取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的佔有;
-
線程執行發生異常,此時JVM會讓線程自動釋放鎖。
如果這個獲取鎖的線程由於I/O或者其他原因(如調用sleep方法)被阻塞了,但是有沒有釋放鎖,其他線程便只能乾巴巴地等待,這會很影響執行效率。
因此就需要一種機制可以不讓等待的線程一直無限期地等待下去(如只等待一定的時間或者能夠響應中斷),通過Lock就可以辦到。
再如:當有多個線程讀取文件時,讀操作和寫操作會發生衝突,寫操作和寫操作會發生衝突,但是讀操作和讀操作不會發生衝突。
如果此時採用synchronized關鍵字就會出現一個問題:如果多個線程只是進行讀操作,所以當一個線程進行讀操作時,其他的線程只能等待無法進行讀操作。
因此就需要 一種機制使得多個線程都只是進行讀操作時,線程之間不會發生衝突,通過Lock就可以辦到。
另外,通過Lock可以知道線程有沒有成功獲取鎖,這是synchronized無法辦到的。
注意:
-
Lock不是Java語言內置的,synchronized是Java語言的關鍵字,因此是內置特性,Lock是一個類(接口),通過這個類可以實現同步訪問;
-
使用synchronized不需要用戶手動去釋放鎖,當synchronized方法或代碼塊執行完後,系統會自動讓線程釋放對鎖的佔用;而Lock則必須要用戶手動釋放鎖,如果沒有主動釋放,就有可能導致出現死鎖。
**使用Lock鎖案例 **
package com.yxl.demo.ThreadTest;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class test5 {
public static void main(String[] args) throws InterruptedException {
TestDemo thread = new TestDemo();
Thread t1 = new Thread(thread,"窗口一");
Thread t2 = new Thread(thread,"窗口二");
t1.start();
t2.start();
}
}
class TestDemo implements Runnable{
//共享的火車票變量
private int count = 100;
//重寫run方法
@Override
public void run() {
while (count > 0) {
sale();
}
}
public void sale() {
Lock lock = new ReentrantLock();
lock.lock();
try {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + "出售 :" + (100 - count + 1));
count--;
}
}catch (Exception e){
}finally {
//一定在finally中釋放鎖
lock.unlock();
}
}
}