在java中,解決同步問題,不少時候都會使用到synchronized和Lock,這二者都是在多線程併發時候常使用的鎖機制。java
synchronized是java中的一個關鍵字,也就是說是java內置的一個特性。當一個線程訪問一個被synchronized修飾的代碼塊,會自動獲取對應的一個鎖,並在執行該代碼塊時,其餘線程想訪問這個代碼塊,會一直處於等待狀態,自有等該線程釋放鎖後,其餘線程進行資源競爭,競爭獲取到鎖的線程才能訪問該代碼塊。bash
線程釋放synchronized修飾的代碼塊鎖的方式有兩種:多線程
採用synchronized關鍵字來實現同步,會致使若是存在多個線程想執行該代碼塊,而當前獲取到鎖的線程又沒有釋放鎖,可想而知,其餘線程只有一隻等待,這將嚴重印象執行效率。Lock鎖機制的出現就是爲了解決該現象。Lock是一個java接口,經過這個接口能夠實現同步,使用Lock時,用戶必須手動進行鎖的釋放,不然容易出現死鎖。 併發
ReentranLock是Lock的惟一實現類。下面簡單介紹一下ReentranLock與synchronized的區別:ide
公平鎖:當線程A獲取訪問該對象,獲取到鎖後,此時內部存在一個計數器num+1,其餘線程想訪問該對象,就會進行排隊等待(等待隊列最前一個線程處於待喚醒狀態),直到線程A釋放鎖(num = 0),此時會喚醒處於待喚醒狀態的線程進行獲取鎖的操做,一直循環。若是線程A再次嘗試獲取該對象鎖是,會檢查該對象鎖釋放已經被佔用,若是被佔用,會作一次是否爲當前線程佔用鎖的判斷,若是是內部計數器num+1,而且不須要進入等待隊列,而是直接回去當前鎖。測試
非公平鎖:當線程A在釋放鎖後,等待對象的線程會進行資源競爭,競爭成功的線程將獲取該鎖,其餘線程繼續睡眠。ui
公平鎖是嚴格的以FIFO的方式進行鎖的競爭,可是非公平鎖是無序的鎖競爭,剛釋放鎖的線程很大程度上能比較快的獲取到鎖,隊列中的線程只能等待,因此非公平鎖可能會有「飢餓」的問題。可是重複的鎖獲取能減少線程之間的切換,而公平鎖則是嚴格的線程切換,這樣對操做系統的影響是比較大的,因此非公平鎖的吞吐量是大於公平鎖的,這也是爲何JDK將非公平鎖做爲默認的實現。spa
下面是接口Lock的方法:操作系統
附上對接口Lock方法的測試,有什麼問題歡迎各位留言評論。線程
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
// ReentrantLock爲Lock的惟一實現類
private Lock lock = new ReentrantLock();
/**
* 測試使用lock 的 lock()方法 :若是鎖已經被其餘線程獲取,則等待
* @param thread
*/
public void testLock(Thread thread){
try {
// 1.獲取鎖
lock.lock();
System.out.println("線程 " + thread.getName() + " 獲取了鎖!");
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("線程 " + thread.getName() + " 釋放了鎖!");
// 必須在 finally 中釋放鎖,防止死鎖
lock.unlock();
}
}
/**
* 測試使用lock 的 lock()方法 :經過這個方法去獲取鎖時,若是線程正在等待獲取鎖,則這個線程可以響應中斷,即中斷線程的等待狀態。
* @param thread
*/
public void testLockInterruptibly(Thread thread){
try {
// 1.獲取鎖
lock.lockInterruptibly();
System.out.println("線程 " + thread.getName() + " 獲取了鎖!");
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("線程 " + thread.getName() + " 釋放了鎖!");
// 必須在 finally 中釋放鎖,防止死鎖
lock.unlock();
}
}
/**
* 測試使用lock 的 tryLock()方法 :若是獲取成功,則返回true,若是獲取失敗(即鎖已被其餘線程獲取),則返回false
* @param thread
*/
public void testTryLock(Thread thread){
if(lock.tryLock()){// 若是獲取到了鎖
try {
System.out.println("線程 " + thread.getName() + " 獲取了鎖!");
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("線程 " + thread.getName() + " 釋放了鎖!");
// 必須在 finally 中釋放鎖,防止死鎖
lock.unlock();
}
}else {
// 沒有獲取到鎖
System.out.println("線程 " + thread.getName() + " 沒有獲取到鎖!");
}
}
/**
* 測試使用lock 的 tryLock(long time, TimeUnit unit)方法 :和tryLock()方法是相似的,只不過區別在於這個方法在拿不到鎖時會等待必定的時間,
* 在時間期限以內若是還拿不到鎖,就返回false。若是若是一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。
* @param thread
*/
public void testTryLock_time_unit(Thread thread){
try {
if(lock.tryLock(1000, TimeUnit.MILLISECONDS)){// 若是獲取到了鎖
try {
System.out.println("線程 " + thread.getName() + " 獲取了鎖!");
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("線程 " + thread.getName() + " 釋放了鎖!");
// 必須在 finally 中釋放鎖,防止死鎖
lock.unlock();
}
}else {
// 沒有獲取到鎖
System.out.println("線程 " + thread.getName() + " 沒有獲取到鎖!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
TestLock testLock = new TestLock();
Thread a = new Thread("A") {
@Override
public void run() {
/*// 測試 lock()
testLock.testLock(Thread.currentThread());*/
/*// 測試 lockInterruptibly()
testLock.testLockInterruptibly(Thread.currentThread());*/
/*// 測試 tryLock()
testLock.testTryLock(Thread.currentThread());*/
/*// 測試 tryLock(long time, TimeUnit unit)
testLock.testTryLock_time_unit(Thread.currentThread());*/
testLock.testTryLock_time_unit(Thread.currentThread());
}
};
Thread b = new Thread("B") {
@Override
public void run() {
testLock.testTryLock(Thread.currentThread());
}
};
a.start();
b.start();
}
}
複製代碼