【Java從入門到頭禿專欄 6】語法篇(五) :多線程 線程池 可見、原子性 并發包 Lambda表達式

目錄

1 多線程

1.1 基本概念

1.2 創建線程的三種方式

1.4 解決線程安全問題的三種方法

1.5 線程通信

1.6 線程狀態

2 線程池

2.1線程池的概念?

2.2 創建并提交任務

3 可見性

3.1 變量不可見性

3.2 變量不可見性的解決方案

4 原子性

4.1 原子性的概念

4.2 保證原子性的方案? ? ?

4.3 原子類的CAS機制

5 多線程的并發包

5.1 ConcurrentHashMap類

?5.2 CountDownLatch類

5.3 CyclicBarrier類

5.4 Semaphore類

5.5? Exchanger類


1 多線程

1.1 基本概念

????????程序(program)為了完成特定的任務,使用某種語言編寫的一組指令的集合,也就是一段靜態的代碼。

????????進程(process):程序加載到內存中的一次執行過程,或者是正在運行中的一個程序。進程作為資源分配的單位,系統在運行時會為每個進程分配不同的內存區域。

????????線程(thread):一個進程可被進一步細化成一個或多個線程,線程就是一個程序內部的一條執行路徑。如果一個程序可以同時并行執行多個線程,我們就稱它是支持多線程的。線程作為調度和執行的單位,每個線程都擁有獨立的運行棧和程序計數器,所有的線程共享進程分配的堆和方法區,都從同一個堆中分配對象訪問相同的變量和對象。這就是的線程之間的通信更加簡便、高效,但是由于共享系統資源也就帶來了安全隱患。

????????單CPU與并發:CPU相當于人的大腦,用來動態的為程序的運行分配內存空間,之所以是動態的是因為一個CPU一次只能執行一個進程,但是同一時間一臺電腦幾乎不可能只開啟一個進程,一個CPU會不停的切換執行多個進程也就是并發執行,由于切換的速度比較快在人類看來計算機就是在同時執行多個進程。

????????多CPU與并行:多CPU是相對于單CPU而言的概念,多CPU就是多個CPU同時執行不同的進程也就是并行執行,與此同時每個CPU還會不停的切換執行多個進程也就是并發執行。

? ? ? ? 并發與并行:舉個例子,比如說今年暑假的抗洪救災現場,需要將裝成袋的沙子搬到決堤口擋水,并發:這里有20袋沙子(相當于20個進程),但是只有一個人來搬(單CPU),這個人搬完一袋換一袋由于換的速度比較快,看起來就好像是20袋沙子一塊被搬一樣。并發和并行同步執行:這里有20袋沙子(相當于20個進程),但是有四個人來搬(多CPU),四個人同時搬就是并行,這四個人搬完各自的一袋換一袋由于換的速度比較快看起來也好像是20袋沙子一塊被搬一樣,這里的每個人搬完換另一袋就叫并發。于是大部分情況下的單CPU的性能要優于多CPU的。

? ? ? ? 一個java應用程序java.exe至少應該包三個線程:main()主線程、gc()垃圾回收線程、異常處理線程。

1.2 創建線程的三種方式

方法一:繼承Thread類

? ? ? ? 四步:創建類并繼承Thread-->重寫run方法-->創建線程對象-->調用start方法

?? 創建線程對象調用start方法才會產生新的線程(start方法底層會先向CPU注冊線程,在調用run方法),如果調用run方法會被當做是一個普通類執行,這樣進程里面也就還只有一個主線程。

?? main方法里面要先創建子線程出來再分配主線程的任務,否則在進程執行的時候會認為只有一個主線程,因為從代碼的執行順序來看此時還沒有創建子線程,從而會導致永遠都是先執行完主線程任務再執行子線程任務。

這樣創建線程的優點是編碼簡單,缺點是通過繼承Thread類創建線程會導致線程類無法在對其他類進行繼承,功能無法通過繼承來拓展(單繼承的局限性)

?Thread的常用API

方法二:實現Runnable接口?

????????五步:創建任務類并實現Runnable接口-->重寫run方法-->創建任務對象-->將任務對象包裝成線程對象-->調用start方法?

這個方法創建線程的缺點:比上一種方法多了一步,下一個方法可以獲取重新寫call方法的返回結果而這個的run方法沒有返回值。優點有:由于任務類沒有繼承任何類,可以繼續繼承其他類拓展功能;同一個任務類可以被包裝成多個線程對象;適合多個線程共享同一個資源;實現解耦操作,任務可以被多個線程共享,任務與任務之間有相互獨立不影響??????

創建線程的簡化寫法(匿名內部類)

?方法三:實現Callable接口

? ? ? ? 六步:創建任務類并實現Callable接口-->重寫call方法-->創建任務對象-->將任務對象包裝成FutureTask對象-->將FutureTask對象包裝成線程對象-->調用start方法?

? ? ? ? 第三種方法和第二種方法的差別就是這個方法可以獲取返回值

?1.3 線程安全問題

? ? ? ??當多個線程操作同一個共享資源的時候就有可能會出現線程安全問題。比如說,小明和小紅有一個共同情侶賬戶里面有100塊錢,小明和小紅同時登錄系統取錢,會出現以下情況:

線程號人員操作結果賬戶余額
1小明查詢余額>=100?true100
2小紅查詢余額>=100?true100
3小明取100100-1000
4小紅取1000-100-100

由于線程的執行時隨機且無法回退的,所以可能會導致兩人都查詢賬戶余額有100塊的情況,線程繼續往后執行就會導致賬戶被兩次取錢成為負值,這肯定是有問題的。

賬戶bean類:

主類:

?取錢任務類:

控制臺運行結果:

??

1.4 解決線程安全問題的三種方法

方法一:同步代碼塊

synchronized(鎖對象) {

? ? ? ? 訪問共享資源的核心代碼;

}

?? 在實例方法中建議使用this作為鎖對象,靜態方法中建議使用類名.class作為鎖對象

方法二:同步方法

在方法的定義時使用synchronized修飾即可

同步方法與同步代碼塊的方法差不多,同步方法的底層是將整個方法都鎖了起來

方法三:Lock顯式鎖

創建鎖對象:

上鎖:

解鎖:

?使用該方法上鎖的話,盡量要按照這種try-catch-finally的方式,否則可能遇到上鎖之后出現異常,此時程序就無法繼續運行,也就是說永遠無法解鎖導致出現問題。

1.5 線程通信

現在有這么一個需求

使用IDEA進行實現代碼

賬戶bean類:

?主類:

取錢任務類:

存錢任務類:

控制臺運行結果:

這是個死循環運行了一會就暫停了截圖?

1.6 線程狀態

?? sleep方法只是計時等待,不會把鎖放開;wait方法是把鎖放開進入等待。

死鎖:

?????????死鎖就是不同的線程同時分別占用著對方需要的鎖不放,都在等待著對方放鎖。出現死鎖之后不會產生任何的異常和提示,只是所有的線程都處于阻塞狀態無法繼續。

死鎖產生的四個必要條件:

  • 互斥使用:即共享資源一次只能被一個線程使用
  • 不可搶占:即線程不能從正在使用共享資源的線程手中奪取資源
  • 請求保持:一個線程在請求另一個線程資源的同時依然占有著那個線程所請求的資源
  • 循環等待:1要2的資源,2要1的資源,形成了一個循環等待

2 線程池

2.1線程池的概念?

? ? ? ? 前面講過,每當我們需要使用線程的時候,不管是使用哪個方法都需要去創建一個線程,實現起來并不難但是會產生一個問題:如果并發的線程數量很多且線程的執行時間都很短的時候,線程的創建和銷毀都需要時間,頻繁的創建銷毀線程就會導致系統的效率大大降低。

? ? ? ? 解決以上問題就用到了線程池的概念,線程池就是一個可以容納固定多個線程的容器,線程池中的線程可以反復使用。線程池中工作線程(PoolWorker)的個數是固定的,而任務接口(Task)想要使用工作線程的話就需要在任務隊列(TaskQueue)中排隊等待,任務執行完畢之后工作線程歸還線程池出于空閑狀態。

2.2 創建并提交任務

創建線程池并指定線程數量:

無返回值的Runnable任務:

有返回值的Callable任務:

??? 線程池對象調用submit(任務對象)方法將任務對象提交給線程池執行,線程池在執行完所有的任務之后并不會直接關閉,而是處于等待狀態等待其他任務的使用,如果沒有其他任務就一直處于等待狀態,可以調用shutdown()方法等待任務執行完畢之后關閉線程池。

3 可見性

3.1 變量不可見性

? ? ? ? 首先,Java專門為多線程定義了一種Java內存模型(Java Memory Model JMM),這種內存模型要不同于單線程的內存模型JVM。JMM描述了Java程序中各種共享變量的訪問規則,以及在JVM中將變零存儲在內存中和從內存中讀取像變量的底層細節。

JMM的規定:

  • 所有的共享變量都存儲于主內存。這里的變量指的是實例變量和類變量,并不包含局部變量,因為局部變量是線程私有的不存在競爭問題。
  • 每個線程有自己的工作內存,里面存放的是從主內存中拷貝來的共享變量副本。
  • 線程對變量的所有操作都在線程的工作內存中完成,而不是直接操作主內存中的共享變量。
  • 不同線程之間也不能訪問對方的工作內存,線程間變量的值傳遞通過主內存中轉完成。

不可見性描述:

?? ? ? ? 并發編程下,也就是說當存在多個線程訪問一個共享資源時,一個線程改變了這個資源的變量值,但是其他線程并不能看到這個變量值的改變,讀取到的依然是變量修改之前的值。以上現象又被稱為是多線程間變量的不可見性

變量不可見性的原理:

3.2 變量不可見性的解決方案

方案一:加鎖

????????對線程任務進行加鎖。其底層原理在于:線程在獲得鎖對象之后會清空線程的工作內存,從主內存中再次拷貝共享變量的值成為共享變量副本,此時線程工作內存中共享變量副本就是最新的變量值了。

方案二:volatile關鍵字修飾

?????????定義變量的時候使用volatile關鍵字進行修飾。其底層原理與加鎖不同的是:volatile關鍵字是在主內存發現有線程對共享變量的值進行修改之后,通知其他線程工作內存中的共享變量副本的值失效,其他線程在訪問共享變量的副本的時候發現值已失效,于是重新拷貝共享變量至工作內存中。

4 原子性

4.1 原子性的概念

????????原子性指的是:一批操作是一個整體,要么同時成功要么同時失敗,不能被其他干擾。volatile只能保證線程之間變量的可見性,但是不能保證變量操作的原子性。? ?

4.2 保證原子性的方案? ? ?

方案一:加鎖

? ? ? ? 加鎖就是對線程任務進行加鎖。加鎖不僅能夠保證線程的原子性,還能保證線程之間變量值修改的可見性。但是加鎖會降低程序的性能,故又有了第二種方法。

方案二:原子類

Java提供了java.util.concurrent.atomic包(簡稱atomic包),包里面有各種類類中有很多方法。

? ? ? ? 原子類包含有很多種,其中包括AtomicInteger、AtomicDouble……對不同數據類型的數據進行操作更新的類,這些類中定義了一些API去代替運算,與普通運算方式的區別在于,這種方法的運算能在不加鎖的情況下保證線程的原子性。

原子類的使用:

原子類中定義了很多的API根據自己的需求選擇使用

從上圖中可以看出來,一個線程執行完所有的任務下一線程再執行,這種模式與前面的上鎖很像,其實原子類就是加鎖機制的高性能版本,在實現加鎖機制保證線程安全的同時又保證了原子性。

4.3 原子類的CAS機制

? ? ? ? CAS的全稱為Compare And Swap譯為先比較再交換,CAS可以將read-modify-check-write操作轉換為原子操作,保證了線程的原子性。CAS機制不鎖任務,任意線程的任何時候都可以操作任務,就是操作完任務之后要將操作前的共享變量副本與主內存中的共享變量值進行對比,一致的話就修改主內存中共享變量的值,不一致的話就將之前的任務操作作廢,重新開啟一次任務(拷貝、修改、對比)。

5 多線程的并發包

5.1 ConcurrentHashMap類

java.util.concurrent.ConcurrentHashMap

在創建HashMap集合的時候使用即可,創建之后即可保證線程安全,類下面的API操作和HashMap一樣,正常使用即可。

?5.2 CountDownLatch類

java.util.concurrent.CountDownLatch

創建一個計數器,用于實現線程執行時的計數等待,使用有參構造創建對象的同時給定計數步數,也就是說等待計數器減幾次,await()方法讓當前線程讓出CPU等待計數器的值清零,countDown()方法可以將計數器的值減1

5.3 CyclicBarrier類

java.util.concurrent.CyclicBarrier

創建一個循環屏障對象,傳入兩個參數阻擋線程個數和一個Runnable任務對象,意思就是屏障阻擋了相應的線程個數之后就執行這個Runnable任務

5.4 Semaphore類

java.util.concurrent.Semaphore

?Semaphore對象的主要作用就是控制線程并發的數量,也就是說使用有參構造創建一個Semaphore對象設置最大允許進入acquire()方法和release()方法之間任務代碼的線程個數。可以用來限制一個資源同一時間的的最大訪問人數,使用synchronized上鎖相當于創建Semaphore對象的時候傳參為1。

5.5? Exchanger類

java.util.concurrent.Exchanger

Exchanger類適用于線程間協作通信的類,利用構造器定義一個Exchanger對象容器使用泛型規定容器暫存數據的類型,可以是無參構造器也可以是有參構造器,兩個參數超時不再交換時間和超時時間單位,調用exchange(V x)方法進行數據交換并返回交換之后對方傳過來的結果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/535133.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535133.shtml
英文地址,請注明出處:http://en.pswp.cn/news/535133.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Java從入門到頭禿專欄 7】語法篇(六) :Lambda表達式(->) 方法引用(::) stream流

目錄 1 Lambda表達式( -> ) ? 2 方法引用( :: ) 3 Stream流 接下來介紹的三種語法叫:Lambda表達式 方法引用 stream流,這三種語法的使用要有特定條件,在一定條件下借助這三種語法可以使代碼十分簡單且優雅,但是不要舍本逐末…

【Java從入門到頭禿專欄 4】語法篇(三) :字符串 數組

目錄 1 String字符串 2 數組 1 String字符串 Java沒有內置的字符串類型,而是在Java類庫中提供了一個預定義類--String。 在Java中把每一個使用雙引號括起來的字符串都看做是String類的一個實例化對象。 String常被稱作是不可變字符串類型,那么有人就有…

【Java從入門到頭禿專欄 8】語法篇(七) :反射 動態代理 注解

目錄 1 反射機制 2 反射的應用:動態代理 3 注解 1 反射機制 反射機制(Reflect Machanism),是指在程序運行期間借助Reflect API獲取任何類的內部信息,并能直接操作對象的內部屬性以及方法,Java本身而言是靜態語言但是由于Java反…

【SSM面向CRUD編程專欄 1】Spring簡介 xml配置文件 依賴注入 數據注入

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

【SSM面向CRUD編程專欄 2】Spring相關API 數據源(連接池)的配置 注解開發 整合junit

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

【SSM面向CRUD編程專欄 4】 Spring集成web環境 SpringMVC初識

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 ?…

IntelliJ IDEA里的項目搞崩了怎么辦,本地歷史版本回退拯救你崩潰的心靈

💥寫在前面: 如果你還沒有讀過雨果的悲慘世界也沒有讀過余華的活著,那你可以看看我今天早上的經歷,如果不想聽我胡侃的話,直接進入正題: 目錄 本地歷史的強大 今天早上打開IntelliJ IDEA繼續ssm模塊的代碼練…

【SSM面向CRUD編程專欄 5】使用SpringMVC進行數據響應以及獲取請求數據

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

【SSM面向CRUD編程專欄 6】springMVC攔截器、異常處理 jdbcTemplate

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

【SSM面向CRUD編程專欄 7】springAop 事務控制

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

【SSM面向CRUD編程專欄 8】一篇博客快速上手使用MyBatis進行CRUD

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

【SSM面向CRUD編程專欄 9】SSM框架整合

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

三萬字速通SSM框架入門知識點,快速上手CRUD

🛫更多ssm知識見SSM_面向CRUD編程專欄 🚕本博客總結自黑馬程序員的ssm框架視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 目…

無法在web.xml或使用此應用程序部署的jar文件中解析絕對uri:[http://java.sun.com/jsp/jstl/core]

問題簡介 本人是在進行一個ssm框架項目的編寫的時候,在數據庫中查詢到所有的商品信息并返回到頁面使用EL表達式進行展現,但是使用tomcat 9.0.58運行的時候報錯會出現以下報錯情況。 頁面報錯: 控制臺報錯: 解決方法 首先看看是不…

check the manual that corresponds to your MySQL server version for the right syntax to use near

首先判斷自己是在什么情況下報的錯,如果是MyBatis的SQL報錯的話,建議直接點擊目錄跳轉到MyBatis時SQL報錯,避免浪費時間。如果本文能夠對你有所幫助的話,還請在評論區多多支持 目錄 🍻運行SQL語句、SQL文件等報錯 &…

MyBatis的逆向工程工具,自動生成數據庫對應的POJO實體類、mapper接口、增刪改查mapper.xml文件

下載MyBatis的逆向工程工具,并解壓縮到一個不包含中文字符的文件夾下,我直接放到了D盤下,下載地址:MyBatis逆向工程工具下載 如何使用MyBatis的逆向工程工具 下載之后使用idea在一個新窗口中打開,選中工具文件之后&am…

『收藏向 期末SSM課設救急』 教你從搭建到測試運行手擼一個SSM項目實戰,附帶源碼,前端頁面、解析和一般遇到的問題(排雷)

🛫ssm知識學習見SSM_面向CRUD編程專欄 🚕本項目來自動力節點的【米米商城】 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 項目…

【SpringBoot 2】(一)基礎知識了解學習

🛫更多知識總結見SpringBoot 2專欄 🚕本篇知識點總結自尚硅谷雷神的視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 ? 目錄…

【SpringBoot 2】(二)快速入門案例HelloWorld

🛫更多知識總結見SpringBoot 2專欄 ( 🚕本篇知識點總結自尚硅谷雷神的視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 ? 目…

【SpringBoot 2】(三)SpringBoot相較于Spring的特點

🛫更多知識總結見SpringBoot 2專欄 🚕本篇知識點總結自尚硅谷雷神的視頻 🚒博主對于該知識尚在學習階段 🚄如果發現存在問題請毫不吝嗇的指出 🚀🚀扎哇太棗糕的博客主頁🚀🚀 ? 目錄…