@[toc]
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();
}
}
}
lock.trylock() 擷取鎖 ,也要結合 try catch 一起使用lock.lock() 擷取鎖
lock.unlock() 釋放鎖,但要在 finally中使用