1. 程式人生 > >從火箭發場景來學習Java多執行緒併發閉鎖物件

從火箭發場景來學習Java多執行緒併發閉鎖物件

從火箭發場景來學習Java多執行緒併發閉鎖物件

倒計時器場景

在我們開發過程中,有時候會使用到倒計時計數器。最簡單的是:int size = 5; 執行後,size—這種方式來實現。但是在多執行緒併發的情況下,這種操作會不安全的。舉個現實中最典型的一個例子:火箭發射的案例。

大家都看過火箭發射的直播吧。火箭在傳送的時候,有很多裝置需要檢查是否都準備就緒。在總控室得到所有裝置都準備就緒後,才會下達發射的命令。我們也知道,火箭發射有很多裝置需要檢驗,這不是一個部門一個一個檢查的,而是多個部門協同配合實現的。如果把一個個部門看作不同的執行緒的話。我們就可以假設:

如果是一個部門一個一個裝置檢查,這就是單執行緒操作的;

如果是多個部門協同配合的話,就是多執行緒的。

所以說,在火箭發射前檢查裝置是 多執行緒情況下進行的。

我們也不知道,不同部門負責檢查的裝置的複雜度不同,速度不同,就會導致有些部門檢查完成的快,有些部門檢查完成的慢。這個過程我們可以理解為不同執行緒在競爭CPU資源的時候不同。

假設有5個部門同時協同工作,這5個部門的操作可以看作是一組操作。因為速度不同,那麼總控室下達發射的命令是以哪個檢查完畢為準呢?是A部門還是B部門或者D部門呢?都不是,總控室下達發射的命令是在得到5個部門都檢查完畢後才會下達發射的命令。我們也可以理解為總控室在得到這一組(五個部門)都操作完成才執行的。此時總控室可以理解為一個執行緒,五個部門一組可以理解一個執行緒組。

從上面現實生活中的案例分析,我們來想想上面的操作用Java程式怎麼實現 ?

使用count—的程式碼實現

模擬不同部門的執行緒:

我們先來看看常規的。使用count--的效果。

模擬總控室的主執行緒:

從上面程式碼中,我們可以看到當計數器count減到0的時候,總控室下達發射命令。這個從邏輯上來說,是正確的,沒問題的。我們來看看執行結果:

執行結果:

從執行結果,我們可以看到,當總控室接收到count =0的指令後,認為各個部門都已經檢查完畢了。所以就下達了發射命令。但是在最後,我們發現火箭已經發射了,部門4和5才向總控室彙報檢查完畢,準備就緒。這種情況是很危險的。因為我們知道火箭的造價是很昂貴的而且凝聚了很多科研人員的心血。如果因為某個部門未檢查完畢就發射而導致火箭發射失敗或者墜落,在現實生活中,這種情況是不允許出現的。

那麼這種情況,在Java中,怎麼解決呢?可以使用countdownlatch這個物件來解決。

Countdownlatch

Countdownlatch是什麼?

先來看看原始碼中怎麼解釋的:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

什麼意思呢?

簡單的來說,是一個同步輔助工具類,執行一個或多個執行緒在等待其他執行緒完成一組操作後再接著執行的工具類。

實現的流程:

通過一個計數器來實現的,計數器的初始值就是要執行的執行緒的數量。每當一個執行緒執行完畢之後,計數器的值就會減一,當計數器的值減少到0的時候,表示所有的執行緒都執行完畢了。然後再閉鎖上等待的其他執行緒就可以恢復正常工作了。

來看看主要的方法

說明:

Sync:是countdownlatch內部類,繼承AbstractQueuedSynchronizer使用AQS狀態來代替計數的。

有參構造器:public CountDownLatch(int count){}

await():等待方法。還有一個帶引數過載的方法。

countdown():執行計數器減1操作的方法。

使用countdownlatch模擬火箭發射前準備程式碼:

我們來看看使用countdownlatch來模擬火箭發射前準備會不會出問題。

來看看模擬部門的執行緒程式碼:

為了保證計數器減一操作不受子執行緒執行結果影響,講count.coundDown()操作放在finally程式碼塊裡面。

再來看看總控室下達發射命令的主執行緒:

在downLatch.await()之後,下達發射命令。

檢視執行結果:

 

我們可以看到,當所有部門都準備就緒後,總控室接收到完成的指令後,下達發射火箭命令。這個流程才是正常的。從執行結果來看也是正常的。

使用場景:

場景1:某執行緒在執行前需要等待其他N個執行緒執行完成之後在執行。

比如:

容器啟動spring 容器的啟動,需要初始化、bean裝配、檢查其他依賴等載入完畢之後,在主執行緒在繼續執行;

在比如:電商中統計庫存問題。我們知道,一個電商專案有很多分類,不同分類下的庫存不一樣。如果要統計當前剩餘總庫存。這個時候,就可以使用其他執行緒統計每個分類下的庫存。等所有分類都統計完成之後,主執行緒在進行彙總操作。

 

關注凱哥:

個人部落格:www.kaigejava.com

個人公眾號:凱哥Java(kaigejava)

相關推薦

火箭場景學習Java執行併發閉鎖物件

從火箭發場景來學習Java多執行緒併發閉鎖物件 倒計時器場景 在我們開發過程中,有時候會使用到倒計時計數器。最簡單的是:int size = 5; 執行後,size—這種方式來實現。但是在多執行緒併發的情況下,這種操作會不安全的。舉個現實中最典型的一個例子:火箭發射的案例。 大家都看過火箭發射的直播吧。火箭在

如何學習Java執行

最近一段時間,我對《Java併發程式設計實踐》這本經典而又有些難懂的書籍,嘗試用了一些簡單有趣、通俗易懂的方式進行解讀,現整理成GitBook(文末有連結),方便大家閱讀。 為什麼要解讀這本書 因為這是一本經典卻又難懂的書。 這本書的經典我想不

跟著例項學習java執行3-synchronized的多種寫法有何區別?

同步程式碼塊是一種有效實現操作原子性的方法,上一章我們講了一些同步的原子操作的基礎。 現在我們回憶一下上一章的兩個問題。 1:不同的synchronized的寫法有什麼區別,又該怎麼寫建立執行緒的程式碼呢? 以class例項物件作為鎖的寫法 寫法1 package com.

Java執行-併發執行

執行緒池有了解嗎? 答: java.util.concurrent.ThreadPoolExecutor 類就是一個執行緒池。客戶端呼叫ThreadPoolExecutor.submit(Runnable task) 提交任務,執行緒池內部維護的工作者執行緒的數量就是該執行緒池的執行

Java執行-併發之synchronized 關鍵字

synchronized 關鍵字 答: 底層實現: 進入時,執行 monitorenter,將計數器 +1,釋放鎖 monitorexit 時,計數器 -1 當一個執行緒判斷到計數器為 0 時,則當前鎖空閒,可以佔用;反之,當前執行緒進入等待狀態 含義

Java執行-併發之sleep() 和 wait(n) 、 wait() 的區別

sleep() 和 wait(n) 、 wait() 的區別 答: sleep 方法:是 Thread 類的靜態方法,當前執行緒將睡眠 n 毫秒,執行緒進入阻塞狀態。當睡眠時間到了,會接觸阻塞,進入可執行狀態,等待 CPU 的到來。睡眠不釋放鎖(如果有的話) wai

Java執行-併發執行產生死鎖的4個必要條件?如何避免死鎖?

多執行緒產生死鎖的4個必要條件? 答: 互斥條件:一個資源每次只能被一個執行緒使用 請求與保持條件:一個執行緒因請求資源而阻塞時,對已獲得的資源保持不放 不剝奪條件:程序已經獲得的資源,在未使用完之前,不能強行剝奪 迴圈等待條件:若干執行緒之間形成一種頭

Java執行-併發執行和程序的區別

執行緒和程序的區別 答: 程序是一個“執行中的程式”,是系統進行資源分配和排程的一個獨立單位 執行緒是程序的一個實體,一個程序中擁有多個執行緒,執行緒之間共享地址空間和其他資源(所以通訊和同步等操作執行緒比程序更加容易) 執行緒上下文的切換比程序上下文切換要快

Java執行-併發之如何制定執行執行順序?

文章目錄 如何讓10個執行緒按照順序列印0123456789? 程式碼如下: 1.建立一個鎖物件類 2.建立一個執行緒類 3.測試類 如何讓10個執行緒按照順序列印012

Java執行併發總結】Thread類的常用方法(join、yield等)---執行的基礎操作篇

 啟動(start)   最基本的操作,呼叫Runnable中的run方法,無返回值。 new Thread(new Test()).start(); 休眠(sleep)  使當前執行緒休眠一段時間,預設為毫秒級,最高可以精確到納秒,呼叫的方法為slee

java 執行併發實質

首先我們都知道多執行緒在獲取共享資源時,往往會出現意想不到的結果,這是為什麼呢?執行緒獲取共享資源的過程如下圖: 首先我們需要了解jvm記憶體結構,在這裡不過多說明,由上圖我們可以知道,在jvm記憶體中分為獨立記憶體和共享記憶體,獨立記憶體是我們每個執行緒獨有的資訊,而

JAVA執行併發Demo

一個最簡單的多執行緒併發demo: 主函式: public class multithreadReq { private static final int THREADNUM = 5;/

一、Java執行併發同步之Semaphore

概念 Semaphore是一種在多執行緒環境下使用的設施,該設施負責協調各個執行緒,用來管理資源,以保證它們能夠正確、合理的使用公共資源的設施,也是作業系統中用於控制程序同步互斥的量。用我們常見的說法就是用來控制併發數。 訊號量是一個非負整數 。 業務場景 以售

Java執行/併發20、Future實現類:FutureTask

FutureTask是future的實現類,它同時實現了兩個介面:Runnable和Future,所以它既可以作為Runnable被執行緒執行,又可以作為Future得到Callable的返回值。 因此我們可以: - 呼叫FutureTask物件的ru

二、Java執行併發同步之CyclicBarrier

概述 CyclicBarrier:可迴圈屏障,允許一組執行緒全部等待的同步輔助工具。一組執行緒互相等待,直到所有執行緒都到達某個公共屏障點(也可以叫同步點) 。它可以在等待執行緒之後重新使用。這個屏障之所以用迴圈修飾,是因為在所有的執行緒釋放彼此之後,這個屏障是

java執行併發系列之閉鎖(Latch)和柵欄(CyclicBarrier)

-閉鎖(Latch) 閉鎖(Latch):一種同步方法,可以延遲執行緒的進度直到執行緒到達某個終點狀態。通俗的講就是,一個閉鎖相當於一扇大門,在大門開啟之前所有執行緒都被阻斷,一旦大門開啟所有執行緒都將通過,但是一旦大門開啟,所有執行緒都通過了,那麼這個閉鎖的狀態就失效了,門

入坑JAVA執行併發(六)死鎖

  在多執行緒的中,因為要保證執行緒安全,需要對一些操作進行加鎖,但是如果操作不當,會造成死鎖,導致程式無法執行下去。   形成死鎖的場景:如果有兩個執行緒,執行緒1和執行緒2,執行緒1執行,獲得鎖A,執行緒2執行,獲得B,執行緒1等待鎖B的釋放,執行緒2等待

入坑JAVA執行併發(五)生產者消費者模式

生產者消費者模式對於理解多執行緒是一個很經典,也很好的例子 資源類: class Resource{ //資源初始化個數 private int init; //資源最大個數 private int Max; p

入坑JAVA執行併發(二)執行的生命週期和常用方法

執行緒的生命週期大致分為五種狀態: 1. 新建: 新建一個執行緒物件。 2.可執行: 啟動執行緒,呼叫start方法或者呼叫執行緒池的excute方法等,此時執行緒會進入可執行執行緒池中,等待獲取CPU的時間片。 3.執行 執行狀態,也就

Java執行併發最佳實踐

使用本地變數 儘量使用本地變數,而不是建立一個類或例項的變數。 使用不可變類 String、Integer等。不可變類可以降低程式碼中需要的同步數量。 最小化鎖的作用域範圍:S=1/(1-a+a/n) a:平行計算部分所佔比例 n:並行處理結點個數 S:加速比 當1-a等於0時,沒有序列只有並