日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 并发编程系列之带你了解多线程

發布時間:2024/9/30 java 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 并发编程系列之带你了解多线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

早期的計算機不包含操作系統,它們從頭到尾執行一個程序,這個程序可以訪問計算機中的所有資源。在這種情況下,每次都只能運行一個程序,對于昂貴的計算機資源來說是一種嚴重的浪費。

操作系統出現后,計算機可以運行多個程序,不同的程序在單獨的進程中運行。操作系統負責為各個獨立的進程分配各種資源。并且不同的進程間可以通過一些通信機制來交換數據,比如:套接字、信號處理器、共享內存、信號量等。

一、了解多線程

1.1 進程與線程

想必大家都聽說過這兩個名詞,它們之間有什么聯系與不同呢?

記得當時上操作系統課時,書上有這么一句話:進程是獨立擁有 cpu 資源的最 小單位,線程是接受 cpu 調度的最小單位。網上看了那么多的解釋,還是覺得書上說的最簡單明了。

進程中可以同時存在多個程序控制流程的線程,線程會共享進程范圍內的資源,因此一個進程可以有多個線程。打個比方,進程就像一個大工廠,而線程就是工廠的工人,多個工人負責協同完成工廠的任務。

1.2 多線程的優勢

  • 發揮多處理器的強大能力
  • 簡化建模過程
  • 簡化異步事件處理機制
  • 響應更靈敏的用戶界面

1.3 多線程安全性問題

多線程是一把雙刃劍,使用多線程時意味著對開發人員有一定的技術要求。可見學會了多線程技術,就能寫出更優雅的代碼了,哈哈~

多個線程同時訪問意味著“共享”變量,這些“共享”變量往往在其生命周期內是可變的,這樣以來就極易出現多線程安全性問題。

什么是線程安全,這里給一個比較準確的定義:當多個線程訪問某各類時,這個類始終都能表現出正確的行為,那么就稱這個類是線程安全的。

二、Java 內存模型

為什么要在多線程專題里涉及到 Java 內存模型呢?我覺得它可以幫助我們更好的理解多線程的工作機制。

比如很多人都聽說過或了解過 volatile 關鍵字,都知道它能保證內存可見性問題,但是理解起來總是太過抽象。如果你了解了 Java 內存模型,它可以很好的幫助你理解這些問題。

Java 內存模型規定了所有的變量都存儲在主內存中(Main Memory)中(可以類比為物理硬件的主內存)。每條線程都有自己的工作內存(Working Memory),線程的工作內存中保存了主內存中的變量的拷貝,線程對變量的所有操作(讀取、賦值)都必須在自己的工作內存中進行,而不能直接讀寫主內存中的變量。

不同的線程之間無法訪問對方工作內存中的變量,線程間變量值的傳遞均需要通過主內存來完成。

如果你對 Java 內存區域了解的話,很容易就會想工作內存、主內存與 Java 內存區域中的堆、棧、方法區是否有一定關系呢?

如果在實例變量的角度來看,主內存對應于 Java 堆中的對象實例數據部分,而工作內存則對應于虛擬機棧中的部分區域。從更低層次來看,主內存直接對應于物理硬件的內存。

三、解決線程安全性問題

使用 Java 創建線程的幾種方式這里就不再贅述了,我們來了解幾種處理多線程安全性問題的方法。

3.1 synchronized 關鍵字

Java 提供了一種內置的鎖機制(synchronized 關鍵字)來保證原子性與內存可見性。關于原子性與內存可見性問題會在講述 volatile 關鍵字時詳細的介紹,感興趣的可以關注后面的文章。

Java 的內置鎖是一種互斥鎖,意味著最多只有一個線程能持有這種鎖。當線程 A 和線程 B 同時訪問臨界資源,如果線程 A 獲取鎖,線程 B 就必須等待或阻塞,A 不釋放 B 就只能等待下去。

由于每次只有一個線程執行內置鎖內的代碼,因此被 synchronized 關鍵字保護的臨界資源會以原子(一組不可分割的單元)的方式執行,多個線程間執行時不會受到干擾,原子性與數據庫事務有相同的含義。

synchronized 關鍵字可以用來修飾方法和代碼塊,如果修飾非靜態方法和同步代碼塊,使用的鎖是當前對象,如果修飾靜態方法和靜態代碼塊,使用的是當前類的 Class 對象作為鎖。

使用方式如下

public class SyncTest {private Integer num = 1;public int numAutoIncrement() {synchronized (this) {return num ++;}}public static void main(String[] args) {SyncTest syncTest = new SyncTest();// 開啟 10 個線程for (int i = 0; i < 10; i++) {new Thread(() -> System.out.println(Thread.currentThread().getName() + ":" + syncTest.numAutoIncrement())).start();}} }

3.2 使用原子類

jdk1.5 之后 java.util.concurrent.atomic 包下引入了諸如 AtomicInteger、AtomicLong 等特殊的原子性變量類。

這些變量類底層使用 CAS 算法與 volatile 關鍵字確保對所有的計數器操作都能保證原子性與可見性,也就解決了多線程安全問題。

使用方式如下

public class SyncTest {private AtomicInteger atomicInteger = new AtomicInteger(1);public int numAutoIncrement() {return atomicInteger.getAndIncrement();}public static void main(String[] args) {SyncTest syncTest = new SyncTest();for (int i = 0; i < 10; i++) {new Thread(() -> System.out.println(Thread.currentThread().getName() + ":" + syncTest.numAutoIncrement())).start();}} }

3.3 使用顯示 Lock 鎖

jdk1.5 之前,解決多線程共享對象訪問的機制只有 synchronized 和 volatile。jdk1.5 新增了一種新的機制:ReentrantLock。ReentrantLock 并不是為替代內置鎖而生的,當內置鎖機制不適用時,可以考慮使用這種更靈活的加鎖機制。

使用方式如下

public class SyncTest {private Lock lock = new ReentrantLock();private Integer num = 1;public int numAutoIncrement() {lock.lock();try {return num++;} finally {lock.unlock();}}public static void main(String[] args) {SyncTest syncTest = new SyncTest();for (int i = 0; i < 10; i++) {new Thread(() -> System.out.println(Thread.currentThread().getName() + ":" + syncTest.numAutoIncrement())).start();}} }

從上面的代碼可以看出來,使用顯示鎖機制相對內置鎖要麻煩一些,使用時要注意必須在 finally 語句塊中釋放鎖,否則當出現異常時,獲取到的鎖永遠不會被釋放,在代碼中存在這種情況無疑是一種定時炸彈。

顯示鎖相較于內置鎖還提供了等待可中斷、公平與非公平等功能,當然還有一個優點是顯示鎖更加靈活。

PS:
這篇博文中很多知識點拿出來都可以單獨寫一篇文章,這里只是總結了一部分重要的知識點,先讓大家對多線程有一個感性的認識。后面會陸續的補充并發編程系列的文章。如果大家覺得寫得還行的話,請持續關注后面的文章。

參考資料

《Java 并發編程實戰》
《深入理解 Java 虛擬機》

總結

以上是生活随笔為你收集整理的Java 并发编程系列之带你了解多线程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。