1. 程式人生 > >多執行緒 共享資源 同步鎖 java Java多執行緒程式設計:Lock

多執行緒 共享資源 同步鎖 java Java多執行緒程式設計:Lock

Java多執行緒程式設計:Lock

 

synchronized是java中的一個關鍵字,也就是說是Java語言內建的特性。那麼為什麼會出現Lock呢?

  如果一個程式碼塊被synchronized修飾了,當一個執行緒獲取了對應的鎖,並執行該程式碼塊時,其他執行緒便只能一直等待,等待獲取鎖的執行緒釋放鎖,而這裡獲取鎖的執行緒釋放鎖會有三種情況:

  1)獲取鎖的執行緒執行完了該程式碼塊,然後執行緒釋放對鎖的佔有;

  2)執行緒執行發生異常,此時JVM會讓執行緒自動釋放鎖。

  3)這個主要是在等待喚醒機制裡面的wait()方法,//在等待的時候立即釋放鎖,方便其他的執行緒使用鎖。而且被喚醒時,就在此處喚醒,

  那麼如果這個獲取鎖的執行緒由於要等待IO或者其他原因(比如呼叫sleep方法)被阻塞了,但是又沒有釋放鎖,其他執行緒便只能乾巴巴地等待,試想一下,這多麼影響程式執行效率。因此我們需要不論程式的程式碼塊執行的如何最終都將鎖物件進行釋放,方便其他執行緒的執行。(此處後面有一個簡單的demo起始就是將鎖物件人工的釋放而且是在finally裡面的執行)

   雖然我們可以理解同步程式碼塊和同步方法的鎖物件問題,但是我們並沒有直接看到在哪裡加上了鎖,在哪裡釋放了鎖,同時為了更好地釋放鎖。
  為了更清晰的表達如何加鎖和釋放鎖,JDK5以後提供了一個新的鎖物件Lock。

  另外,通過Lock可以知道執行緒有沒有成功獲取到鎖。這個是synchronized無法辦到的。

  總結一下,也就是說Lock提供了比synchronized更多的功能。但是要注意以下幾點:

  1)Lock不是Java語言內建的,synchronized是Java語言的關鍵字,因此是內建特性。Lock是一個類,通過這個類可以實現同步訪問;

      2)synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在程式碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過程式碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中

     3)在資源競爭不是很激烈的情況下,Synchronized的效能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的效能會下降幾十倍,

但是ReetrantLock的效能能維持常態;

 

 

一、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 }

 

synchronized是java中的一個關鍵字,也就是說是Java語言內建的特性。那麼為什麼會出現Lock呢?

  如果一個程式碼塊被synchronized修飾了,當一個執行緒獲取了對應的鎖,並執行該程式碼塊時,其他執行緒便只能一直等待,等待獲取鎖的執行緒釋放鎖,而這裡獲取鎖的執行緒釋放鎖會有三種情況:

  1)獲取鎖的執行緒執行完了該程式碼塊,然後執行緒釋放對鎖的佔有;

  2)執行緒執行發生異常,此時JVM會讓執行緒自動釋放鎖。

  3)這個主要是在等待喚醒機制裡面的wait()方法,//在等待的時候立即釋放鎖,方便其他的執行緒使用鎖。而且被喚醒時,就在此處喚醒,

  那麼如果這個獲取鎖的執行緒由於要等待IO或者其他原因(比如呼叫sleep方法)被阻塞了,但是又沒有釋放鎖,其他執行緒便只能乾巴巴地等待,試想一下,這多麼影響程式執行效率。因此我們需要不論程式的程式碼塊執行的如何最終都將鎖物件進行釋放,方便其他執行緒的執行。(此處後面有一個簡單的demo起始就是將鎖物件人工的釋放而且是在finally裡面的執行)

   雖然我們可以理解同步程式碼塊和同步方法的鎖物件問題,但是我們並沒有直接看到在哪裡加上了鎖,在哪裡釋放了鎖,同時為了更好地釋放鎖。
  為了更清晰的表達如何加鎖和釋放鎖,JDK5以後提供了一個新的鎖物件Lock。

  另外,通過Lock可以知道執行緒有沒有成功獲取到鎖。這個是synchronized無法辦到的。

  總結一下,也就是說Lock提供了比synchronized更多的功能。但是要注意以下幾點:

  1)Lock不是Java語言內建的,synchronized是Java語言的關鍵字,因此是內建特性。Lock是一個類,通過這個類可以實現同步訪問;

      2)synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在程式碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過程式碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中

     3)在資源競爭不是很激烈的情況下,Synchronized的效能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的效能會下降幾十倍,

但是ReetrantLock的效能能維持常態;

 

 

一、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 }