摘要:本人郵箱歡迎轉載轉載請注明網址代碼已經全部托管有需要的同學自行下載理論主要提供更多鎖的特性讓線程能獲取同步方法或同步塊的執行它們提供更多的靈活的結果能擁有不多的屬性并且可以配合類提供多樣的組合一個是控制多線程去訪問一個共享的資源一般來說一個
理論本人郵箱:
歡迎轉載,轉載請注明網址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經全部托管github有需要的同學自行下載
java.util.concurrent.locks.Lock: Lock主要提供更多鎖的特性讓線程能獲取同步方法或同步塊的執行.它們提供更多的靈活的結果,能擁有不多的屬性,并且可以配合Condition類提供多樣的組合.
一個Lock是控制多線程去訪問一個共享的資源.一般來說,一個lock會提供更高級的方法去訪問共享資源:比如在某一個時間點,只能有一個線程獲得lock,那么這個這個lock就能訪問所有的共享資源.然而,有一種lock允許多個線程同時訪問共享資源,這種lock就是讀寫鎖ReadWriteLock.
一般使用synchronized的同步方法或同步塊對每個對象提供的絕對的鎖去訪問它們, 但也是所有的鎖的請求或釋放都發生阻塞.當多線程訪問共享資料,只要有一個鎖獲取了請求,那么其他鎖則必須被釋放掉.
在synchronized的同步方法或同步塊中,若使用監視鎖會是編程更加簡單.它已經幫助我們把在訪問鎖的時候屏蔽掉一下程序公共的錯誤.而且使我們能更加靈活用鎖進行多線程操作.
一般lock的用法如下:
Lock l = ...; l.lock(); try{ }finally( l.unlock(); )
這是為了確保我們在使用的時候,如果執行方法出現異常,也能正常的釋放鎖.
編碼講了那么多還是通過編碼來學習感覺更加實際點.我們還是用之前那個售票系統
票類 Ticket
public class Ticket { private static final int DEFAULT_TICKET_COUNT = 1000; private int count = DEFAULT_TICKET_COUNT; //票的總數 private int buyedCount = 0; private Object o = new Object(); public boolean buyTicket(int count) throws InterruptedException { if (this.count - count < 0){ Thread.sleep(10); return false; }else{ this.count = this.count - count; Thread.sleep(1); this.buyedCount = this.buyedCount + count; return true; } } public int getCount() { return count; } public int getBuyedCount() { return buyedCount; } public int getAllCount(){ return count + buyedCount; } }
然后再寫一個售票類 TicketRunnable
public class TicketRunnable implements Runnable{ private Ticket ticket; private Random random; private Lock lock; public TicketRunnable(Ticket ticket, Lock lock) { this.ticket = ticket; this.lock = lock; random = new Random(); } @Override public void run() { for (int i = 0; i < 5; i ++) { lock.lock(); try { int count = random.nextInt(10) + 1; boolean success = ticket.buyTicket(count); System.out.println(String.format("%s打算買%d張票,買票%s了,還剩下%d張票,總共賣掉%d張票, 總票數%d", Thread.currentThread().getName(), count, success ? "成功" : "失敗", ticket.getCount(), ticket.getBuyedCount(), ticket.getAllCount())); if (!success) { break; } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
然后寫個程序測試一下
public class SyncThreadTest { public static void main(String[] args) throws InterruptedException { Listthreads = new ArrayList<>(); Ticket ticket = new Ticket(); Lock lock = new ReentrantLock(); for (int i = 0; i < 20; i ++){ threads.add(new Thread(new TicketRunnable(ticket, lock))); } for (Thread thread : threads){ thread.start(); } } }
運行一下程序,截取部分輸出
Thread-7打算買8張票,買票成功了,還剩下654張票,總共賣掉346張票, 總票數1000 Thread-8打算買1張票,買票成功了,還剩下653張票,總共賣掉347張票, 總票數1000 Thread-9打算買5張票,買票成功了,還剩下648張票,總共賣掉352張票, 總票數1000 Thread-10打算買10張票,買票成功了,還剩下638張票,總共賣掉362張票, 總票數1000 Thread-11打算買3張票,買票成功了,還剩下635張票,總共賣掉365張票, 總票數1000 Thread-12打算買2張票,買票成功了,還剩下633張票,總共賣掉367張票, 總票數1000 Thread-13打算買10張票,買票成功了,還剩下623張票,總共賣掉377張票, 總票數1000 Thread-14打算買5張票,買票成功了,還剩下618張票,總共賣掉382張票, 總票數1000 Thread-15打算買10張票,買票成功了,還剩下608張票,總共賣掉392張票, 總票數1000 Thread-16打算買2張票,買票成功了,還剩下606張票,總共賣掉394張票, 總票數1000 Thread-17打算買2張票,買票成功了,還剩下604張票,總共賣掉396張票, 總票數1000 Thread-18打算買1張票,買票成功了,還剩下603張票,總共賣掉397張票, 總票數1000 Thread-19打算買6張票,買票成功了,還剩下597張票,總共賣掉403張票, 總票數1000 Thread-0打算買8張票,買票成功了,還剩下589張票,總共賣掉411張票, 總票數1000 Thread-1打算買2張票,買票成功了,還剩下587張票,總共賣掉413張票, 總票數1000 Thread-2打算買8張票,買票成功了,還剩下579張票,總共賣掉421張票, 總票數1000 Thread-3打算買5張票,買票成功了,還剩下574張票,總共賣掉426張票, 總票數1000 Thread-4打算買6張票,買票成功了,還剩下568張票,總共賣掉432張票, 總票數1000 Thread-5打算買1張票,買票成功了,還剩下567張票,總共賣掉433張票, 總票數1000 Thread-6打算買3張票,買票成功了,還剩下564張票,總共賣掉436張票, 總票數1000 Thread-7打算買1張票,買票成功了,還剩下563張票,總共賣掉437張票, 總票數1000 Thread-8打算買5張票,買票成功了,還剩下558張票,總共賣掉442張票, 總票數1000 Thread-9打算買8張票,買票成功了,還剩下550張票,總共賣掉450張票, 總票數1000 Thread-10打算買4張票,買票成功了,還剩下546張票,總共賣掉454張票, 總票數1000 Thread-11打算買5張票,買票成功了,還剩下541張票,總共賣掉459張票, 總票數1000 Thread-12打算買6張票,買票成功了,還剩下535張票,總共賣掉465張票, 總票數1000 Thread-13打算買1張票,買票成功了,還剩下534張票,總共賣掉466張票, 總票數1000 Thread-14打算買8張票,買票成功了,還剩下526張票,總共賣掉474張票, 總票數1000 Thread-15打算買2張票,買票成功了,還剩下524張票,總共賣掉476張票, 總票數1000 Thread-16打算買10張票,買票成功了,還剩下514張票,總共賣掉486張票, 總票數1000
發現運行結果都是正確的
現在嘗試使用lock.tryLock()方法.不管能不能獲得鎖,每個線程都必須賣出5次票,修改TicketRunnable
public class TicketRunnable implements Runnable{ private Ticket ticket; private Random random; private Lock lock; public TicketRunnable(Ticket ticket, Lock lock) { this.ticket = ticket; this.lock = lock; random = new Random(); } @Override public void run() { for (int i = 0; i < 5; ) { if(lock.tryLock()){ try { int count = random.nextInt(10) + 1; boolean success = ticket.buyTicket(count); System.out.println(String.format("%s打算買%d張票,買票%s了,還剩下%d張票,總共賣掉%d張票, 總票數%d", Thread.currentThread().getName(), count, success ? "成功" : "失敗", ticket.getCount(), ticket.getBuyedCount(), ticket.getAllCount())); if (!success) { break; } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); i ++; } }else{ System.out.println(Thread.currentThread().getName() + " 買票系統被占用,嘗試獲取鎖失敗."); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
截取部分運行結果
Thread-11打算買7張票,買票成功了,還剩下613張票,總共賣掉387張票, 總票數1000 Thread-11打算買2張票,買票成功了,還剩下611張票,總共賣掉389張票, 總票數1000 Thread-11打算買7張票,買票成功了,還剩下604張票,總共賣掉396張票, 總票數1000 Thread-11打算買3張票,買票成功了,還剩下601張票,總共賣掉399張票, 總票數1000 Thread-11打算買4張票,買票成功了,還剩下597張票,總共賣掉403張票, 總票數1000 Thread-12 買票系統被占用,嘗試獲取鎖失敗. Thread-10 買票系統被占用,嘗試獲取鎖失敗. Thread-16 買票系統被占用,嘗試獲取鎖失敗. Thread-19打算買2張票,買票成功了,還剩下595張票,總共賣掉405張票, 總票數1000 Thread-19打算買8張票,買票成功了,還剩下587張票,總共賣掉413張票, 總票數1000 Thread-19打算買1張票,買票成功了,還剩下586張票,總共賣掉414張票, 總票數1000 Thread-19打算買5張票,買票成功了,還剩下581張票,總共賣掉419張票, 總票數1000 Thread-19打算買1張票,買票成功了,還剩下580張票,總共賣掉420張票, 總票數1000
發現程序也是正常的.
原理Lock.lock() 當前線程嘗試獲取一個鎖,如果這個鎖獲取不到,則當前線程會一直休眠直到獲取這個鎖.
Lock.lockInterruptibly() 讓當前線程獲取一個鎖,如果鎖可以用,則直接返回.否則當前線程會一直休眠直到一下兩種情況中的其中一個發生:
當前線程獲取到這個鎖
其他線程打斷當前線程, 打斷當前線程獲取鎖的操作是允許的.
Lock.tryLock() 嘗試獲得一個鎖,如果鎖是可用的,則直接返回ture,并獲取到這個鎖.否則,直接返回false
Lock.tryLock(long time, TimeUnit unit) 在某一段時間內嘗試獲取一個鎖,如果鎖可用,則直接返回true,否則等待超時返回fasle
Lock.unlock() 釋放鎖
Lock.newCondition() 這個后面的章節再談論
打賞如果覺得我的文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧個人場(幫我點贊或推薦一下)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67059.html
摘要:初始時,為,當調用方法時,線程的加,當調用方法時,如果為,則調用線程進入阻塞狀態。該對象一般供監視診斷工具確定線程受阻塞的原因時使用。 showImg(https://segmentfault.com/img/remote/1460000016012503); 本文首發于一世流云的專欄:https://segmentfault.com/blog... 一、LockSupport類簡介...
摘要:本人郵箱歡迎轉載轉載請注明網址代碼已經全部托管有需要的同學自行下載引言在寫五多線程之類時我們暫時忽略掉的一個方法那就是這個方法返回一個現在我們這章就重點講這個東東是什么以及怎么使用理論的中文翻譯是狀態沒錯這個就是讓多線程在不同狀態切換其他線 本人郵箱: 歡迎轉載,轉載請注明網址 http://blog.csdn.net/tianshi_kcogithub: https://github...
摘要:前情提要深入理解內存模型四鎖的釋放獲取建立的關系鎖是并發編程中最重要的同步機制。鎖內存語義的實現本文將借助的源代碼,來分析鎖內存語義的具體實現機制。請看下篇深入理解內存模型六 前情提要 深入理解Java內存模型(四)—— volatile 鎖的釋放-獲取建立的happens before 關系 鎖是java并發編程中最重要的同步機制。鎖除了讓臨界區互斥執行外,還可以讓釋放鎖的線程向...
摘要:開始獲取鎖終于輪到出場了,的調用過程和完全一樣,同樣拿不到鎖,然后加入到等待隊列隊尾然后,在阻塞前需要把前驅結點的狀態置為,以確保將來可以被喚醒至此,的執行也暫告一段落了安心得在等待隊列中睡覺。 showImg(https://segmentfault.com/img/remote/1460000016012467); 本文首發于一世流云的專欄:https://segmentfault...
摘要:公平策略在多個線程爭用鎖的情況下,公平策略傾向于將訪問權授予等待時間最長的線程。使用方式的典型調用方式如下二類原理的源碼非常簡單,它通過內部類實現了框架,接口的實現僅僅是對的的簡單封裝,參見原理多線程進階七鎖框架獨占功能剖析 showImg(https://segmentfault.com/img/remote/1460000016012582); 本文首發于一世流云的專欄:https...
閱讀 891·2023-04-26 01:37
閱讀 3367·2021-09-02 15:40
閱讀 955·2021-09-01 10:29
閱讀 2887·2019-08-29 17:05
閱讀 3418·2019-08-28 18:02
閱讀 1180·2019-08-28 18:00
閱讀 1483·2019-08-26 11:00
閱讀 2602·2019-08-26 10:27