国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java并發編程 - 基礎

2019-11-06 06:18:10
字體:
來源:轉載
供稿:網友

并發的歷史

操作系統的發展使得多個程序能夠同時運行, 由操作系統來分配資源, 如果需要的話, 進程會通過一些原始的機制相互通信, 主要分為消息傳遞和共享內存兩種:

消息傳遞: Socket, 信號處理(signal handlers), 信號量(semaphores)和文件等.

共享內存

線程共享其所屬進程的內存地址空間, 因此所有同一進程中的線程訪問相同的變量, 并從同一個堆中分配對象, 這相對于進程間通信(inter-PRocess)機制來說實現了良好的數據共享. 但是如果沒有明確的同步來管理共享數據, 一個線程可能會修改其他線程正在使用的數據, 產生意外的結果.


線程簡介

線程優先級

java線程中, 通過一個int變量priority來控制優先級, 范圍為1~10, 通過setPriority(int)方法來修改優先級, 默認優先級是5, 操作系統通常會忽略自己手動設定的線程優先級(比如Mac OS X, Ubuntu等), 作為程序開發者一般也不需要手動調整

線程的狀態

一共有6種可能的狀態:

狀態名稱 說明
NEW 初始狀態, 僅被構建, 沒有啟用start()方法
RUNNABLE 可運行狀態, 將操作系統中定義的’就緒’和’運行’統稱為’RUNNABLE’
BLOCKED 阻塞狀態, 需要獲取鎖
WAITING 等待狀態, 需要其他線程發出通知或者中斷, 然后重新競爭鎖
TIMED_WAITING 定時等待狀態, 和WAITING類似, 不過不會無限等待,具有一個超時自動返回的功能, 不會引起鎖持有狀況的變化
TERMINATED 終止狀態, 線程已執行完畢

可以使用jstack工具來進行查看運行時線程的信息, 步驟如下:

使用jps命令查看Java進程;找出當前運行程序的進程號, 這里以2100為例, 運行jstack 2100即可.

Java線程狀態變遷示意圖:

Java線程狀態變遷示意圖

Daemon線程

Daemon線程是一種后臺支持型線程, 因為它主要被用作程序中后臺調度以及支持性工作. 當一個JVM中不存在非Daemon線程的時候, JVM將會立即退出(所以不能在finally塊中執行關閉或者清理資源的邏輯)

線程間通信

volatile和synchronized關鍵字

實際上是通過共享內存實現的線程間通信.

通知/等待機制

是任何Java對象都具備的, 這些方法定義在java.lang.Object上:

方法名稱 描述
notify() 通知一個在對象上等待的線程, 使其從wait()方法返回, 而返回的前提是該線程獲取到了對象的鎖
notifyAll() 通知所有等待在該對象上的線程
wait() 調用該方法的線程進入WAITING狀態, 同時釋放對象鎖, 只有等待另外線程的通知或被中斷才會返回
wait(long) 定時等待, 單位毫秒, 超時返回
wait(long, int) 更細粒度的定時, 可以達到納秒級別

等待/通知的經典范式

就是消費者/生產者模型

Thread.join()的使用

實際上是通知/等待機制的一種實現.

ThreadLocal的使用

是線程變量, 以ThreadLocal對象為鍵, 任意對象為值的存儲結構. 這個結構是與線程對象綁定的, 也就是說即使是使用線程不安全的數據結構, 如此包裝后也可以安全使用.


并發編程中的挑戰

并發編程中有許多單線程程序中沒有的挑戰.

上下文切換

即使是單核CPU也支持多線程執行代碼, CPU會通過給每個線程分配CPU時間片來實現這個機制. 時間片一般是幾十毫秒. 當前任務執行一個時間片后會切換到下一個任務, 但是在切換前會保存上一個任務的狀態, 以便下次切換回這個任務時, 可以再加載這個任務的狀態. 所以任務從保存到再加載的過程就是一次上下文切換. 上下文切換會影響多線程的執行速度.

并發執行的速度不一定比串行快, 因為線程有創建和上下文切換的開銷. 當并發運算次數較少的時候, 上下文切換的開銷會顯著影響累積計算時間.

如何較少上下文切換

無鎖并發編程

多線程競爭鎖時, 會引起上下文切換, 避免使用鎖的方法舉例: 通過將數據的ID按照Hash算法取模分段, 不同的線程處理不同段的數據.

CAS算法

Java的Atomic包使用的就是CAS算法來更新數據, 不需要加鎖, 舉例: AutomicLong類型

使用最少線程

避免大量線程處于等待狀態

協程

在單線程里實現多任務的調度, 在單線程里維持多個任務間的切換.

死鎖

避免死鎖的幾個方法

避免一個線程同時獲取多個鎖;嘗試使用定時鎖, 使用lock.tryLock(timeout)來替代使用內部鎖機制;

如何保證線程安全

使用無狀態對象

無狀態對象永遠是線程安全的

這里以一個Servlet為例, 說明什么叫做無狀態:

因為Servlet對象不包含屬性, 也沒有引用其他類的屬性, 只有本地變量. 本地變量唯一的存儲在本線程的棧中, 只有執行線程(本Servlet)才能訪問, 所以是線程安全的.

使用原子操作

讀-改-寫 不是原子的, 例如count++check-then-run, 不是原子的, 例如: if (i != null) i = new SomeClass();

無狀態+單個內置原子變量=線程安全, 但是兩個及以上的原子變量!=線程安全

為了維持狀態一致性, 必須將相關的狀態變量在同一個原子操作內更新

注意

并不是說將一個類的所有方法都標注成synchronized, 然后這個類就是線程安全的了, 舉個例子, 如果兩個屬性之間需要同步更新, 然后分別提供了setter方法, 那么在類外使用的時候, 就有可能引發安全問題.


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 灵璧县| 巩留县| 桓仁| 攀枝花市| 托克逊县| 霍州市| 玉龙| 宜君县| 上林县| 浮山县| 凤台县| 砚山县| 滁州市| 绥德县| 垣曲县| 东乌珠穆沁旗| 昭平县| 玉林市| 泸西县| 上蔡县| 噶尔县| 常德市| 潍坊市| 高邑县| 新密市| 锡林郭勒盟| 大连市| 南漳县| 西畴县| 阿克陶县| 神农架林区| 开封市| 城口县| 江口县| 西吉县| 新野县| 叶城县| 九龙城区| 科尔| 广德县| 获嘉县|