Lock鎖方式解決線程安全問題
阿新 • • 發佈:2019-04-19
override code main 異同 xtend 分析 font port 應該
在JDK5.0之後新增加了一種更強大的線程同步機制---通過顯示定義同步鎖來實現線程同步解決線程安全問題。同步鎖使用Lock對象充當。
java.util.concurrent.locks.lock接口是控制多個線程對共享資源進行訪問的工具。鎖提供了對共享資源的單獨訪問,每一次只能有一個線程對Lock對象加鎖,並且線程在訪問共享資源之前應該先加鎖。
ReentrantLock類實現了Lock,它擁有和synchronized相同的並發行和內存語義,在實現線程安全的控制中,比較常用的就是ReentrantLock,可以實現顯示的加鎖和釋放鎖,比較靈活。
使用Lock鎖的方式模擬多線程共同賣票的情景:
1 package com.baozi.java; 2 3 import java.util.concurrent.locks.Lock; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 public class WinowTest4 { 7 public static void main(String[] args) { 8 Window4 w1 = new Window4(); 9 Window4 w2 = new Window4(); 10 Window4 w3 = newWindow4(); 11 w1.start(); 12 w2.start(); 13 w3.start(); 14 } 15 } 16 17 //通過繼承Thread類的方法來實現多線程 18 class Window4 extends Thread { 19 private static int ticket = 100; 20 private static Lock lock = new ReentrantLock(); 21 22 @Override 23 public voidrun() { 24 while (true) { 25 try { 26 lock.lock(); 27 if (ticket > 0) { 28 try { 29 Thread.sleep(100); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 System.out.println(Thread.currentThread().getName() + ":" + ticket--); 34 } else { 35 break; 36 } 37 } finally { 38 lock.unlock(); 39 } 40 41 } 42 } 43 }
synchronized和Lock 的異同:
同:兩者都是解決線程安全問題
異:
- synchronized關鍵字定義的不管是同步代碼塊還是同步方法在執行完成之後都是自動的釋放同步監視器(這是一種隱式鎖,出了作用域隱式鎖將自動的釋放)
- lock需要手動的上鎖啟動同步和手動解鎖結束同步;
- Lock只有代碼塊鎖,沒辦法對某一方法上鎖
- Lock鎖比較靈活,JVM只需要花費較小的代價來實現線程的調度,性能更好並且有更好的擴展性;
這是一個應用實例:
有兩個用戶,分三次往同一個賬戶中存錢,每次每一個人都是存1000元。
分析:
- 是否是多線程問題:是,兩個用戶是兩個線程
- 是否有共享數據:賬戶余額
- 是否有線程安全問題:有,當兩個線程同時往裏邊存錢時候,如果不進行安全控制,賬戶余額會出現錯誤
- 所以考慮使用同步機制解決線程安全問題
1 package com.baozi.exer; 2 3 import java.util.concurrent.locks.Lock; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 /** 7 * 銀行有一個賬戶,兩個儲戶分別向裏邊存三次錢,每次都存一千元, 8 */ 9 public class AccountTest { 10 public static void main(String[] args) { 11 Account account = new Account(0); 12 Customer c1 = new Customer(account); 13 Customer c2 = new Customer(account); 14 c2.setName("儲戶2"); 15 c1.setName("儲戶1"); 16 c1.start(); 17 c2.start(); 18 } 19 } 20 21 class Account { 22 private int balance; 23 Lock lock = new ReentrantLock(); 24 25 public Account(int balance) { 26 this.balance = balance; 27 } 28 29 public void setBalance(int amt) { 30 lock.lock(); 31 try { 32 if (amt > 0) { 33 balance += amt; 34 try { 35 Thread.sleep(100); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 System.out.println(Thread.currentThread().getName() + " :當前余額為: " + balance); 40 } 41 } finally { 42 lock.unlock(); 43 } 44 } 45 46 47 } 48 49 class Customer extends Thread { 50 51 private Account account; 52 53 public Customer(Account account) { 54 this.account = account; 55 } 56 57 @Override 58 public void run() { 59 for (int i = 0; i < 3; i++) { 60 account.setBalance(1000); 61 } 62 } 63 }
Lock鎖方式解決線程安全問題