synchronized是java中的一個關鍵字,也就是說是Java語言內置的特性。那麼爲何會出現Lock呢?html
若是一個代碼塊被synchronized修飾了,當一個線程獲取了對應的鎖,並執行該代碼塊時,其餘線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這裏獲取鎖的線程釋放鎖會有三種狀況:java
1)獲取鎖的線程執行完了該代碼塊,而後線程釋放對鎖的佔有;編程
2)線程執行發生異常,此時JVM會讓線程自動釋放鎖。多線程
3)這個主要是在等待喚醒機制裏面的wait()方法,//在等待的時候當即釋放鎖,方便其餘的線程使用鎖。並且被喚醒時,就在此處喚醒,ide
那麼若是這個獲取鎖的線程因爲要等待IO或者其餘緣由(好比調用sleep方法)被阻塞了,可是又沒有釋放鎖,其餘線程便只能乾巴巴地等待,試想一下,這多麼影響程序執行效率。所以咱們須要不論程序的代碼塊執行的如何最終都將鎖對象進行釋放,方便其餘線程的執行。(此處後面有一個簡單的demo起始就是將鎖對象人工的釋放並且是在finally裏面的執行)工具
雖然咱們能夠理解同步代碼塊和同步方法的鎖對象問題,可是咱們並無直接看到在哪裏加上了鎖,在哪裏釋放了鎖,同時爲了更好地釋放鎖。
爲了更清晰的表達如何加鎖和釋放鎖,JDK5之後提供了一個新的鎖對象Lock。post
另外,經過Lock能夠知道線程有沒有成功獲取到鎖。這個是synchronized沒法辦到的。性能
總結一下,也就是說Lock提供了比synchronized更多的功能。可是要注意如下幾點:測試
1)Lock不是Java語言內置的,synchronized是Java語言的關鍵字,所以是內置特性。Lock是一個類,經過這個類能夠實現同步訪問;spa
2)synchronized是在JVM層面上實現的,不但能夠經過一些監控工具監控synchronized的鎖定,並且在代碼執行時出現異常,JVM會自動釋放鎖定,可是使用Lock則不行,lock是經過代碼實現的,要保證鎖定必定會被釋放,就必須將unLock()放到finally{}中
3)在資源競爭不是很激烈的狀況下,Synchronized的性能要優於ReetrantLock,可是在資源競爭很激烈的狀況下,Synchronized的性能會降低幾十倍,
可是ReetrantLock的性能能維持常態;
1、Lock鎖的簡單使用
1 import java.util.concurrent.locks.Lock; 2 import java.util.concurrent.locks.ReentrantLock; 3 4 public class SellTicket implements Runnable { 5 6 // 定義票 7 private int tickets = 100; 8 9 // 定義鎖對象 10 private Lock lock = new ReentrantLock(); 11 12 @Override 13 public void run() { 14 while (true) { 15 try { 16 // 加鎖 17 lock.lock(); 18 if (tickets > 0) { 19 try { 20 Thread.sleep(100); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 System.out.println(Thread.currentThread().getName() 25 + "正在出售第" + (tickets--) + "張票"); 26 } 27 } finally { 28 // 釋放鎖 29 lock.unlock(); 30 } 31 } 32 } 33 //注意 這種寫法 就是爲了防止程序異常 而不放鎖 並且還能夠清晰的看到那些線程拿到了鎖 34 }
出異常的測試 多線程
1 import java.util.concurrent.locks.Lock; 2 import java.util.concurrent.locks.ReentrantLock; 3 4 public class SellTicket implements Runnable { 5 6 // 定義票 7 private int tickets = 100; 8 9 // 定義鎖對象 10 private Lock lock = new ReentrantLock(); 11 12 @Override 13 public void run() { 14 while (true) { 15 try { 16 // 加鎖 17 lock.lock(); 18 if (tickets > 0) { 19 try { 20 Thread.sleep(100); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 System.out.println(Thread.currentThread().getName() 25 + "正在出售第" + (tickets--) + "張票"); 26 }
int i=1/0; 27 } finally { 28 // 釋放鎖 29 lock.unlock(); 30 } 31 } 32 } 33 //注意 這種寫法 就是爲了防止程序異常 而不放鎖 並且還能夠清晰的看到那些線程拿到了鎖 34 }
下面是測試類
1 public class RunnableDemo { 2 public static void main(String[] args) { 3 SellTicketsRunnable str = new SellTicketsRunnable(); 4 5 Thread tr1 = new Thread(str, "tr1"); 6 Thread tr2 = new Thread(str, "tr2"); 7 Thread tr3 = new Thread(str, "tr3"); 8 9 // 10 tr1.start(); 11 tr2.start(); 12 tr3.start(); 13 } 14 }