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