日本午夜一本久久久综合_免费日韩电影_亚洲激情视频_国产超碰91_不卡的电视剧免费网站有什么_佐佐木明希av_成人精品免费网站_久久婷婷国产91天堂综合精品_91在线观看地址_亚洲自拍欧美另类_日韩黄色三级在线观看_一区在线中文字幕

歡迎您訪問Java 8并發教程:利用同步關鍵字、鎖和信號量同步訪問共享變量!

Java 8并發教程:利用同步關鍵字、鎖和信號量同步訪問共享變量

更新時間:2025-05-09 09:13:12作者:佚名

原始文字:Java 8并發教程:同步

翻譯:費隆

協議:CC BY-NC-SA 4.0

歡迎來到我的Java8并發教程的第二部分。本指南將教您如何在Java 8中使用簡單易懂的代碼示例在Java 8中進行編程。這是一系列教程的第二部分。在接下來的15分鐘內,您將學習如何通過同步關鍵字,鎖和信號量同步訪問共享變量。

本文中顯示的中心概念也適用于Java的較舊版本,但是代碼示例適用于Java 8permit是什么意思?怎么讀,并嚴重依賴Lambda表達式和新的并發功能。如果您還不熟悉Lambda,我建議您先閱讀我的Java 8教程。

為簡單起見,本教程的代碼示例使用此處定義的兩個輔助功能睡眠(秒)和停止(執行程序)。

同步

在上一章中,我們學會了如何通過執行器服務同時執行代碼。當我們編寫這種多線程代碼時,我們需要特別注意同時訪問共享變量。假設我們打算增加一個可以通過多個線程同時訪問的整數。

我們使用rezement()方法定義計數字段以添加計數:

int count = 0;

void increment() { ? ?count = count + 1; }

當多個線程同時調用此方法時,我們將遇到大麻煩:

ExecutorService executor = Executors.newFixedThreadPool(2);
IntStream.range(0, 10000)
 ? ?.forEach(i -> executor.submit(this::increment));
stop(executor);
System.out.println(count); ?// 9965

我們看不到計數為10000的結果,并且每次執行上述代碼的實際結果都不同。原因是我們在不同的線程上共享可變變量,并且沒有用于可變訪問的同步機制,從而創造了種族條件。

添加一個值需要三個步驟:(1)讀取當前值,(2)將此值添加到一個,(3)將新值寫入變量。如果兩個線程同時執行,則有可能同時執行兩個線程,并且將讀取相同的當前值。這將導致寫作無效,因此實際結果將很小。在上面的示例中,異步對計數的并發訪問丟失了35個增量操作,但是在自己執行代碼時,您會看到不同的結果。

幸運的是,Java很久以前就支持了與同步關鍵字的線程同步。在增加計數時,我們可以使用同步固定上述比賽條件。

synchronized void incrementSync() {
 ? ?count = count + 1;
}

當我們同時調用regrementSync()時,我們獲得了10000的預期結果。不再次出現比賽條件,并且在每個代碼執行中的結果穩定:

ExecutorService executor = Executors.newFixedThreadPool(2);
IntStream.range(0, 10000)
 ? ?.forEach(i -> executor.submit(this::incrementSync));
stop(executor);
System.out.println(count); ?// 10000

同步關鍵字也可以在語句塊中使用:

void incrementSync() {
? ?synchronized (this) { ? ? ? ?count = count + 1; ? ?} }

Java在內部使用所謂的“監視器”(也稱為顯示器鎖或固有鎖)來管理同步。監視器綁定到對象,例如,當使用同步方法時,每個方法都會為相應的對象共享同一監視器。

所有隱式監視器都實現了重進入功能。重新進入意味著鎖定與當前線綁定。線程可以安全地獲取相同的鎖多次,而無需創建僵局(例如,同步方法調用同一對象的另一種同步方法)。

并發API支持各種顯式鎖,由鎖定接口指定這些鎖以替換同步隱式鎖。鎖支持多種細粒度控制方法,因此它們比隱式監視器具有更多的開銷。

標準JDK中提供了一些鎖的實現,并在以下各章中顯示。

重新進入

重新輸入鎖類是一種靜音類,其行為與通過同步但功能擴展的隱式監視器相同。就像其名稱一樣,此鎖會像隱式監視器一樣實現重新進入功能。

使用Reentrantlock后,讓我們看一下上面的示例。

ReentrantLock lock = new ReentrantLock();
int count = 0;

void increment() { ? ?lock.lock();
? ?try { ? ? ? ?count++; ? ?} finally { ? ? ? ?lock.unlock(); ? ?} }

可以通過鎖()獲得鎖,并通過unlock()釋放。將您的代碼包裹在一個嘗試的障礙物中以確保在特殊情況下解鎖,這一點非常重要。此方法是線程安全的,就像同步復制品一樣。如果另一個線程已經收到鎖,則再次調用鎖()將阻止當前線程,直到鎖定鎖定為止。只有一個線程可以在任何給定時間內獲取鎖。

鎖定到顆粒控件支持多種方法,如以下示例:

executor.submit(() -> {
 ? ?lock.lock();
? ?try { ? ? ? ?sleep(1); ? ?} finally { ? ? ? ?lock.unlock(); ? ?} }); executor.submit(() -> { ? ?System.out.println("Locked: " + lock.isLocked()); ? ?System.out.println("Held by me: " + lock.isHeldByCurrentThread());
? ?boolean locked = lock.tryLock(); ? ?System.out.println("Lock acquired: " + locked); }); stop(executor);

第一個任務獲得鎖后的一秒鐘,第二個任務獲取了有關鎖當前狀態的不同信息。

Locked: true
Held by me: false
Lock acquired: false

Trylock()方法是鎖定()方法的替代方法,該方法試圖在不阻止當前線程的情況下固定鎖定。在訪問任何共享的可突變變量之前,必須使用布爾結果來檢查是否已獲取鎖定。

ReadWritelock

ReadWritelock接口指定了另一種類型的鎖定,包括一對鎖定鎖,用于讀寫訪問。讀寫鎖的想法是,只要沒有線程編寫變量,同時讀取可變變量通常是安全的。因此,只要沒有螺紋固定寫鎖定,就可以同時由多個線程保存讀取鎖。這可以改善性能和吞吐量,因為讀取比寫作更頻繁。

ExecutorService executor = Executors.newFixedThreadPool(2);
Map map = new HashMap<>();
ReadWriteLock lock = new ReentrantReadWriteLock();
executor.submit(() -> {
 ? ?lock.writeLock().lock();
? ?try { ? ? ? ?sleep(1); ? ? ? ?map.put("foo", "bar"); ? ?} finally { ? ? ? ?lock.writeLock().unlock(); ? ?} });

暫停一秒鐘后,上面的示例首先獲取寫鎖以在地圖上添加新值。在完成此任務之前,啟動了另外兩個任務,試圖閱讀地圖中的元素并暫停一秒鐘:

Runnable readTask = () -> {
 ? ?lock.readLock().lock();
? ?try { ? ? ? ?System.out.println(map.get("foo")); ? ? ? ?sleep(1); ? ?} finally { ? ? ? ?lock.readLock().unlock(); ? ?} }; executor.submit(readTask); executor.submit(readTask); stop(executor);

執行此代碼示例時permit是什么意思?怎么讀,您會注意到兩個讀取任務需要等待寫任務完成。寫入鎖定后,將同時執行兩個讀取任務,并同時打印結果。他們不需要等待彼此完成,因為只要沒有其他線程獲得寫鎖,就可以同步獲得讀取鎖。

Stampedlock

Java 8帶有一個名為Stampedlock的新鎖,它也支持讀寫鎖,就像上面的示例一樣。與ReadWritelock不同,Stampedlock的鎖定方法返回表示為長的標記。您可以使用這些標記釋放鎖定,或檢查鎖是否有效。此外,Stampedlock支持另一種稱為樂觀鎖定的模式。

讓我們使用Stampedlock而不是ReadWritelock重寫上面的示例:

ExecutorService executor = Executors.newFixedThreadPool(2);
Map map = new HashMap<>();
StampedLock lock = new StampedLock();
executor.submit(() -> {
? ?long stamp = lock.writeLock();
? ?try { ? ? ? ?sleep(1); ? ? ? ?map.put("foo", "bar"); ? ?} finally { ? ? ? ?lock.unlockWrite(stamp); ? ?} }); Runnable readTask = () -> {
? ?long stamp = lock.readLock();
? ?try { ? ? ? ?System.out.println(map.get("foo")); ? ? ? ?sleep(1); ? ?} finally { ? ? ? ?lock.unlockRead(stamp); ? ?} }; executor.submit(readTask); executor.submit(readTask); stop(executor);

通過ReadLock()或Writelock()獲取讀取鎖或寫鎖定的標簽,該標簽可在以后在最后塊中解鎖。請記住,Stampedlock不會實現重新進入功能。每個鎖定的呼叫都會返回一個新標簽,并在沒有可用鎖定時將其阻止,即使同一線程已經接管了鎖。因此,您需要額外的注意不要僵局。

像以前的ReadWritelock示例一樣,兩個讀取任務都需要等待發布寫鎖。然后,兩個讀取任務同時將信息打印到控制臺網校頭條,因為只要沒有線程獲得寫鎖,多個讀取操作就不會互相阻止。

以下示例顯示了樂觀的鎖:

ExecutorService executor = Executors.newFixedThreadPool(2);
StampedLock lock = new StampedLock();
executor.submit(() -> {
? ?long stamp = lock.tryOptimisticRead();
? ?try { ? ? ? ?System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); ? ? ? ?sleep(1); ? ? ? ?System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); ? ? ? ?sleep(2); ? ? ? ?System.out.println("Optimistic Lock Valid: " + lock.validate(stamp)); ? ?} finally { ? ? ? ?lock.unlock(stamp); ? ?} }); executor.submit(() -> {
? ?long stamp = lock.writeLock();
? ?try { ? ? ? ?System.out.println("Write Lock acquired"); ? ? ? ?sleep(2); ? ?} finally { ? ? ? ?lock.unlock(stamp); ? ? ? ?System.out.println("Write done"); ? ?} }); stop(executor);

通過調用TryOptimisticRead()獲得樂觀的讀取鎖,該鎖總是在不阻止當前線程的情況下返回標簽,而不管鎖定是否實際可用。如果已收到寫鎖,則返回的標記等于0。您需要始終檢查標記是否有效。

執行上述代碼將產生以下輸出:

Optimistic Lock Valid: true
Write Lock acquired
Optimistic Lock Valid: false
Write done
Optimistic Lock Valid: false

樂觀的鎖僅在獲得鎖后是有效的。與普通讀取鎖不同,樂觀的鎖不會阻止其他線程同時獲得寫鎖。在第一個線程暫停一秒鐘后,第二個線程在不等待釋放樂觀的讀鎖的情況下獲取寫鎖。目前,樂觀的讀鎖不再有效。即使釋放寫鎖,樂觀的讀取鎖仍然處于無效狀態。

因此,使用樂觀的鎖時,您需要在訪問任何共享變量后每次檢查鎖定,以確保讀取鎖定仍然有效。

有時,將讀取鎖轉換為寫入鎖定是非常實用的,而無需重新解鎖和鎖定。為此目的,StampedLock提供了TryConvertTowritelock()方法,如以下目的:

ExecutorService executor = Executors.newFixedThreadPool(2);
StampedLock lock = new StampedLock();
executor.submit(() -> {
? ?long stamp = lock.readLock();
? ?try {
? ? ? ?if (count == 0) { ? ? ? ? ? ?stamp = lock.tryConvertToWriteLock(stamp);
? ? ? ? ? ?if (stamp == 0L) { ? ? ? ? ? ? ? ?System.out.println("Could not convert to write lock"); ? ? ? ? ? ? ? ?stamp = lock.writeLock(); ? ? ? ? ? ?} ? ? ? ? ? ?count = 23; ? ? ? ?} ? ? ? ?System.out.println(count); ? ?} finally { ? ? ? ?lock.unlock(stamp); ? ?} }); stop(executor);

第一個任務將獲取讀取鎖,并將計數字段的當前值打印到控制臺。但是,如果當前值為零,我們希望將其分配給23。我們首先需要將讀取鎖轉換為寫入鎖定,以避免從其他線程中破壞潛在的并發訪問。對TryConvertTowriteLock()的調用不會阻止,但可能會返回零標記,表明當前沒有寫鎖。在這種情況下,我們調用Writelock()阻止當前線程,直到有一個可用的寫鎖。

信號

除鎖外,并發API還支持計數信號量。但是,鎖通常用于互斥變量或資源的互斥訪問,信號量可以維護整體訪問權限。這在某些不同的情況下非常有用,例如,當您需要限制程序的一部分并發訪問總數時。

這是一個示例,演示了如何限制通過睡眠模擬的長期運行任務的訪問(5):

ExecutorService executor = Executors.newFixedThreadPool(10);
Semaphore semaphore = new Semaphore(5);
Runnable longRunningTask = () -> {
? ?boolean permit = false;
? ?try { ? ? ? ?permit = semaphore.tryAcquire(1, TimeUnit.SECONDS);
? ? ? ?if (permit) { ? ? ? ? ? ?System.out.println("Semaphore acquired"); ? ? ? ? ? ?sleep(5); ? ? ? ?} else { ? ? ? ? ? ?System.out.println("Could not acquire semaphore"); ? ? ? ?} ? ?} catch (InterruptedException e) {
? ? ? ?throw new IllegalStateException(e); ? ?} finally {
? ? ? ?if (permit) { ? ? ? ? ? ?semaphore.release(); ? ? ? ?} ? ?} } IntStream.range(0, 10) ? ?.forEach(i -> executor.submit(longRunningTask)); stop(executor);

執行人可以同時運行10個任務,但是我們使用Size 5的信號量,因此我們將同時訪問5限制為5。在特殊情況下,使用try-Finally代碼塊合理地釋放信號量很重要。

執行上述代碼會產生以下結果:

Semaphore acquired
Semaphore acquired
Semaphore acquired
Semaphore acquired
Semaphore acquired
Could not acquire semaphore
Could not acquire semaphore
Could not acquire semaphore
Could not acquire semaphore
Could not acquire semaphore

信號量限制了對長達5個線程模擬(5)模擬的長期運行任務的訪問。隨后的每個TryAcquire()調用將打印結果,該結果無法在等待一秒鐘的等待時間之后獲得控制臺的信號量。

這是我系列并發教程的第二部分。將來會發布更多零件,因此請等待。和以前一樣,您可以在GitHub上找到此文檔的所有示例代碼,因此請隨時訂購此存儲庫并自己嘗試。

為您推薦

英語詞匯量對成績影響大,掌握pictures含義及用法很關鍵

pictures英語怎么讀今天我們要掌握的英語單詞就是pictures。上面為同學們解釋了pictures英語怎么讀,并且整理了pictures的相關知識點,希望對同學們有幫助。

2025-05-09 09:53

英語學習超有趣!掌握特定詞匯用法及語言現象很關鍵

如果你把它翻譯成“越過山丘”,從本義出發是沒有錯的,如果你要穿過某座山,是可以這么說的。river.(我沒有沿著河走,而是翻過了小山)。既然本義是翻過山丘,那么比喻一個人的巔峰狀態或者事業翻越過頂點,開始走下坡路還是有點道理的,我們漢語不是有“物極必反”的說法嗎?

2025-05-07 21:33

thankfully什么意思_thankfully怎么讀_thankfully翻譯_thankfully用法_thankfully詞組_同反義詞

thankfully的基本釋義為 基本解釋 adv. (用以表示高興或寬慰)幸虧;高興地,感激地等等。貝語網校(www.inrixtraffic.com.cn)為您提供thankfully發音,英語單詞thankfully的音標,thankfully中文意思,thankfully的過去式,thankfully雙語例句等相關英語知識。

2025-05-07 12:40

thankful什么意思_thankful怎么讀_thankful翻譯_thankful用法_thankful詞組_同反義詞

thankful的基本釋義為 基本解釋 adj. 感謝的,感激的;欣慰的等等。貝語網校(www.inrixtraffic.com.cn)為您提供thankful發音,英語單詞thankful的音標,thankful中文意思,thankful的過去式,thankful雙語例句等相關英語知識。

2025-05-07 12:40

thais什么意思_thais怎么讀_thais翻譯_thais用法_thais詞組_同反義詞

thais的基本釋義為 基本解釋 n. 泰國人,泰國語( Thai的名詞復數 );[電影]泰愛斯等等。貝語網校(www.inrixtraffic.com.cn)為您提供thais發音,英語單詞thais的音標,thais中文意思,thais的過去式,thais雙語例句等相關英語知識。

2025-05-07 12:39

textbooks什么意思_textbooks怎么讀_textbooks翻譯_textbooks用法_textbooks詞組_同反義詞

textbooks的基本釋義為 基本解釋 n. 教科書,課本( textbook的名詞復數 )等等。貝語網校(www.inrixtraffic.com.cn)為您提供textbooks發音,英語單詞textbooks的音標,textbooks中文意思,textbooks的過去式,textbooks雙語例句等相關英語知識。

2025-05-07 12:38

加載中...
国产午夜精品久久久久久免费视| 欧美日本一道本| 丝袜中文在线| 99亚洲国产精品| 亚洲一级淫片| 欧美国产视频一区| 亚洲成人自拍一区| 26uuu亚洲电影| 国产日韩精品视频| 国产一区二区久久| 国产69精品久久久久9| 黄色成人91| 分分操这里只有精品| 国产精品一品视频| 一本色道久久综合狠狠躁篇怎么玩| 国产劲爆久久| 国产精品av电影| 国产精品mv在线观看| 国产精品免费久久久| 四虎国产精品免费观看| 欧美一区在线直播| 亚洲精品在线播放| 久久精品青青大伊人av| xf在线a精品一区二区视频网站| 成人高清dvd| 色999日韩国产欧美一区二区| 国产精品丝袜在线播放| 熟女视频一区二区三区| 欧美日韩中文一区| 菁菁伊人国产精品| 日韩精品在线中文字幕| 欧美一区二区私人影院日本| 99九九热只有国产精品| 国产wwwxx| 伊人亚洲福利一区二区三区| 国产一区二区你懂的| 可以在线观看的av| 国产精品丝袜久久久久久高清| 中文字幕欧美日本乱码一线二线| 欧美aa免费在线| 日本精品视频一区| 91精品麻豆日日躁夜夜躁| 91精品婷婷国产综合久久| 日本免费看黄色| 国产精品视频自在线| 成人ar影院免费观看视频| 天天影视久久综合| 成人午夜电影在线播放| 国产三级av在线| 国产精自产拍久久久久久| 欧美一区 二区| 亚洲图片都市激情| 亚洲曰韩产成在线| 精品国产精品网麻豆系列| 手机福利小视频在线播放| 亚洲一卡二卡区| 欧美欧美午夜aⅴ在线观看| av影视在线看| 成人福利免费观看| 久久高清免费| 免费黄视频网站| 日本久久中文字幕| 亚洲女爱视频在线| 精品在线播放| 中文字幕av在线| 奇门遁甲1982国语版免费观看高清| 久久精品免视看| 欧美三级午夜理伦三级在线观看| 日本a级片免费| 97婷婷大伊香蕉精品视频| 日韩av激情| 亚洲成av人影片在线观看| 9191久久久久久久久久久| 精品动漫3d一区二区三区免费版| 青草久久伊人| 豆国产97在线| 欧美精品一卡二卡| 久久久久国产精品一区二区| 91精品久久| 狠狠躁天天躁日日躁欧美| 亚洲最快最全在线视频| 欧美国产综合| 色天使综合视频| 北条麻妃在线观看| 黄色av免费在线看| 欧美精品hd| 亚洲人成毛片在线播放| 69久久夜色精品国产69| xxx成人少妇69| 色综合中文字幕国产| av在线不卡免费观看| 免费高清完整在线观看| 强开小嫩苞一区二区三区网站| 久久成人精品电影| 麻豆freexxxx性91精品| 日韩欧美自拍| 人人精品久久| 亚洲精品自拍动漫在线| 日韩经典中文字幕一区| 免费看日本毛片| 你懂的一区二区三区| 三级在线看中文字幕完整版| 成人综合av| 伊人久久青青草| 男人搞女人网站| 亚洲va久久久噜噜噜久久天堂| 国产偷国产偷亚洲高清97cao| 久精品免费视频| 国产乱国产乱300精品| 天天在线视频色| 黄页网站视频在线观看| 成人福利视频在线观看| 蜜桃传媒视频麻豆一区| 国产精品黄页免费高清在线观看| 国产厕所精品在线观看| 欧美特级aaa| 国产一区二区在线免费| 精品久久一区二区| 日本一区二区三级电影在线观看| 久久精品国产www456c0m| 免费在线国产视频| 男人天堂av片| 成人免费网站在线观看| 亚洲天堂成人在线视频| 亚洲最新视频在线播放| 精品一区二区综合| 91成人精品在线| 日本一区二区三区四区| 亚洲大片一区二区三区| 国产欧美一区二区色老头| 少妇精品视频在线观看| 加勒比一区二区三区在线| 国产精品久久久久9999爆乳| 91成人福利在线观看| 77777影视视频在线观看| 九九精品在线视频| 久久99热这里只有精品国产| 热久久这里只有| 91精品久久久久久久久久入口 | 亚洲视频分类| 亚洲欧美日韩国产另类专区| 9l视频自拍蝌蚪9l视频成人| 成人一区视频| av中文字幕一区二区| 不卡一区二区在线| 国产黄色精品视频| 91丝袜呻吟高潮美腿白嫩在线观看| 在线精品视频一区二区三四 | 亚洲国产精品久久久久蝴蝶传媒| blacked蜜桃精品一区| 国模私拍视频| 天堂av资源在线观看| 免费**毛片在线| 国产福利一区视频| 嗯啊主人调教在线播放视频| 成人在线中文| 久久老女人爱爱| 国产女主播在线观看| sis001亚洲原创区| 久久看人人摘| 国产成人精品影院| 亚洲va男人天堂| 久久国产精品偷| 日韩成人小视频| 欧美日韩亚州综合| 一级日本不卡的影视| 99riav久久精品riav| 天天揉久久久久亚洲精品| 成人性生交大合| 香蕉成人伊视频在线观看| 好男人看片在线观看免费观看国语| 美日韩黄色大片| 国产精品欧美激情在线观看| 久久综合九色欧美狠狠| 国产+人+亚洲| 两个人的视频www国产精品| 日韩国产中文字幕| 欧美日韩在线亚洲一区蜜芽| 黄色成人av在线| 亚洲一线二线三线视频| ㊣最新国产の精品bt伙计久久| av一区二区三区| 国产精品综合视频| 中文字幕av一区二区三区人| 国产色综合久久| 久久国产情侣| 99热这里只有精品在线播放| 50度灰在线观看| 综合一区中文字幕| 天堂社区 天堂综合网 天堂资源最新版| 91福利入口| av激情久久| 国产精品日韩一区二区三区| 国产成人成网站在线播放青青| 亚洲自拍偷拍区| 97在线免费视频| 久热av在线| 亚洲国产综合在线看不卡| 亚洲在线视频免费观看| 久久午夜a级毛片|