同步控制
- synchronized 擴展:重入鎖
- 重入鎖來代替synchronized充岛,在Jdk1.6以后 synchronized的性能與重入鎖性能差不多。
- 重入鎖的實現(xiàn)
public static ReentrantLock lookLock= new ReentrantLock();
public static int i=0;
public void run() {
for(int j=0; j<100000;j++) {
lookLock.lock(); //加鎖
lookLock.lock();
try {
i++;
} catch (Exception e) {
e.printStackTrace();
}finally {
lookLock.unlock();
lookLock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock reenterLock=new ReenterLock();
Thread t1=new Thread(reenterLock);
Thread t2=new Thread(reenterLock);
t1.start(); t2.start();
t1.join();t2.join();
System.out.println(i);
}
- 在上述代碼中我們使用了重入鎖來保護臨界區(qū)資源i,確保程序的操作的安全性耕蝉。我們在使用重入鎖的時候需要顯示的指定何時加鎖崔梗,何時釋放鎖。必須釋放鎖不然其他線程沒有機會訪問臨界區(qū)了垒在。
- 我們在代碼上還實現(xiàn)了多次加鎖的控制蒜魄,同一個線程可以加入多個鎖來控制 ,但是釋放的時候加了 幾個鎖就要釋放幾個鎖场躯。不然其他線程也無法進入臨界區(qū)谈为。
中斷響應
- 我們在使用synchronized 來加鎖的話,那么結果只有兩種可能 一是獲得鎖繼續(xù)執(zhí)行踢关。二是 繼續(xù)等待伞鲫。但是我們使用重入鎖就可以使其中斷。
- 鎖申請等待限時
- 除了我們在等待外部通知之外签舞,避免死鎖還有另外一種方法秕脓。就是限時等待。我們可以給定一個等待的時候后儒搭。如果線程很長時間拿不到鎖吠架,等待時間到了那么讓其自動放棄。
我們使用重入鎖的tryLock()方法接受兩個參數(shù)搂鲫,一個表示等待時長诵肛,另外一個表示計時單位。并且 該方法也可以不帶參數(shù)直接運行默穴,在嘗試的時候能獲得到鎖,就會立即返回褪秀,當鎖被其他線程占用的時候當前線程不會進行等待蓄诽,立即返回false. 不會產生等待。因此不會產生死鎖媒吗。代碼如下
public class TryLock implements Runnable {
public static ReentrantLock lock1 =new ReentrantLock();
public static ReentrantLock lock2 =new ReentrantLock();
int lock;
public TryLock(int lock) {
this.lock=lock;
}
public void run() {
if(lock==1) {
while(true) {
if(lock1.tryLock()) {
try {
try {
Thread.sleep(500);
} catch (Exception e) {
}
if(lock2.tryLock()) {
try {
System.out.println(Thread.currentThread().getId() +":My Job done");
return ;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
}
}
else {
while(true) {
if(lock2.tryLock()) {
try {
try {
Thread.sleep(500);
} catch (Exception e) {
}
if(lock1.tryLock()) {
try {
System.out.println(Thread.currentThread().getId() +"My Job done");
return ;
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
}
}
}
public static void main(String[] args) {
TryLock r1=new TryLock(1);
TryLock r2=new TryLock(2);
Thread t1 =new Thread(r1);
Thread t2 =new Thread(r2);
t1.start();
t2.start();
}
}
死鎖產生了結果
- 公平鎖
- 大多數(shù)情況下仑氛,鎖的申請都是非公平的。如果我們使用的是synchronized 來加鎖闸英,產生的鎖就是非公平的锯岖。但是我們可以使用重入鎖允許我們對其公平性進行設置。 方法為ReentrantLock(boolean fair)甫何; 當 fair 為true 時出吹,代表鎖是公平的,但是使用公平鎖 需要維護一個有序的隊列辙喂,就會造成性能降低捶牢。因此我們在默認情況下不使用公平鎖鸠珠。
- 整理ReentrantLock 的幾個方法如下:
- lock():獲得鎖 ,吐過鎖被占用 秋麸,則等待渐排;
- lockInterruptibly(): 獲得鎖,單會優(yōu)先響應中斷灸蟆;
- tryLock(); 嘗試獲得鎖驯耻,成功返回true,失敗返回false;不等待立即返回炒考。
- tryLock(long time,TimeUnit unit): 給定時間內獲得鎖可缚。
- unlock(); 釋放鎖。
在重入鎖實現(xiàn)中 主要包含三個元素:
- 使用原子狀態(tài)票腰,原子操作使用CAS操作來存儲當前鎖的狀態(tài)城看,判斷鎖是否被別的線程持有。
- 等待隊列杏慰。所有沒有請求到鎖的線程测柠,會被放入等待隊列中進行等待,待有線程釋放后 系統(tǒng)就能從隊列中喚醒一個線程缘滥,繼續(xù)工作轰胁。
- 阻塞park()和unpark,用來掛起和恢復線程朝扼。沒有得到鎖的線程將會被掛起赃阀。