java.util.concurrent.locksjava
對於線程安全咱們前面使用了synchronized關鍵字,對於線程的協做咱們使用Object.wait()和Object.notify()。在JDK1.5中java爲咱們提供了Lock來實現與它們相同的功能,而且性能優於它們,在JDK1.6時,JDK對synchronized作了優化,在性能上兩種方式差距不大了。安全
synchronized修飾的代碼塊,當一個線程獲取了對應的鎖,並執行該代碼塊時,其餘線程便只能一直等待,等待獲取鎖的線程釋放鎖,若是沒有釋放則須要無限的等待下去。獲取鎖的線程釋放鎖只會有兩種狀況:性能
一、獲取鎖的線程執行完了該代碼塊,而後線程釋放對鎖的佔有。優化
二、線程執行發生異常,此時JVM會讓線程自動釋放鎖。spa
Lock與synchronized對比:線程
一、Lock不是Java語言內置的,synchronized是Java語言的關鍵字,所以是內置特性。Lock是一個類,經過這個類能夠實現同步訪問。code
二、synchronized不須要手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完以後,系統會自動讓線程釋放對鎖的佔用;而Lock則必需要用戶去手動釋放鎖,若是沒有主動釋放鎖,就有可能致使出現死鎖現象。blog
public interface Lock { //用來獲取鎖。若是鎖已被其餘線程獲取,則進行等待。 void lock(); // 當經過這個方法去獲取鎖時,若是線程正在等待獲取鎖,則這個線程可以響應中斷,即中斷線程的等待狀態 void lockInterruptibly() throws InterruptedException; //它表示用來嘗試獲取鎖,若是獲取成功,則返回true,若是獲取失敗(即鎖已被其餘線程獲取),則返回false boolean tryLock(); //與tryLock()方法是相似的,只不過區別在於這個方法在拿不到鎖時會等待必定的時間,在時間期限以內若是還拿不到鎖,就返回false。若是若是一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //釋放鎖 void unlock(); Condition newCondition(); }
一、Lock與unlock
Lock用於獲取鎖,但它不會主動釋放鎖因此須要與unlock()配合使用。通常在使用Lock時必須在try{}catch{}塊中進行,而且將釋放鎖的操做放在finally塊中進行,以保證鎖必定被被釋放,防止死鎖的發生。接口
package com.jalja.base.threadTest; import java.util.concurrent.locks.ReentrantLock; public class LockTest implements Runnable{ public static ReentrantLock lock=new ReentrantLock(); public static int c=0; public void run() { for(int i=0;i<1000;i++){ lock.lock();//獲取鎖 try { System.out.println(Thread.currentThread().getName()+"得到鎖"); System.out.println(Thread.currentThread().getName()+"====>"+c); c++; } catch (Exception e) { e.printStackTrace(); }finally{ System.out.println(Thread.currentThread().getName()+"釋放鎖"); lock.unlock();//釋放鎖 } } } public static void main(String[] args) { LockTest lt=new LockTest(); Thread thread1=new Thread(lt); Thread thread2=new Thread(lt); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(c); } }
注意:同一個線程能夠連續得到同一把鎖,但也必須釋放相同次數的鎖。容許下面的寫法get
lock.lock();//獲取鎖 lock.lock(); lock.lock(); try { System.out.println(Thread.currentThread().getName()+"得到鎖"); System.out.println(Thread.currentThread().getName()+"====>"+c); c++; } catch (Exception e) { e.printStackTrace(); }finally{ System.out.println(Thread.currentThread().getName()+"釋放鎖"); lock.unlock();//釋放鎖 lock.unlock();//釋放鎖 lock.unlock();//釋放鎖 }
二、獲取鎖等待時間tryLock(long time, TimeUnit unit)
若是你約朋友打籃球,約定時間到了你朋友尚未出現,你等1小時後仍是沒到,我想你確定會掃興的離去。對於線程來講也應該時這樣的,由於一般咱們是沒法判斷一個線程爲何會沒法得到鎖,但咱們能夠給該線程一個獲取鎖的時間限制,若是到時間尚未獲取到鎖,則放棄獲取鎖。
package com.jalja.base.threadTest; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class TryLockTest implements Runnable{ public static ReentrantLock lock=new ReentrantLock(); private static int m=0; public void run() { try { if(lock.tryLock(1, TimeUnit.SECONDS)){//設置獲取鎖的等待時長1秒 System.out.println(Thread.currentThread().getName()+"得到鎖"); m++; //Thread.sleep(2000);//設置休眠2秒 }else{ System.out.println(Thread.currentThread().getName()+"未得到鎖"); } } catch (Exception e) { e.printStackTrace(); }finally{ if(lock.isHeldByCurrentThread()){ lock.unlock(); } } } public static void main(String[] args) { TryLockTest thread1=new TryLockTest(); TryLockTest thread2=new TryLockTest(); Thread th1=new Thread(thread1); Thread th2=new Thread(thread2); th1.start(); th2.start(); try { //讓main線程等待th一、th2線程執行完畢後,再繼續執行 th1.join(); th2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(m); } }
執行結果:
Thread-0得到鎖 Thread-1得到鎖 2
該代碼就是讓線程在鎖請求中,最多等待1秒,若是超過一秒沒有得到鎖就返回false,若是得到了鎖就返回true,根據執行結果能夠看出Thread-1線程在1秒內得到了鎖。
咱們開啓註釋 //Thread.sleep(2000);就會發現Thread-1或Thread-0必定會有一個是未得到鎖,這是由於佔用鎖的線程時間是2秒,而等待鎖的線程等待時間是1秒,因此在1秒後的瞬間它就放棄了請求鎖操做。