日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java線程的5個使用技巧

瀏覽:101日期:2022-09-06 10:09:51

Java線程有哪些不太為人所知的技巧與用法?

蘿卜白菜各有所愛。像我就喜歡Java。學無止境,這也是我喜歡它的一個原因。日常工作中你所用到的工具,通常都有些你從來沒有了解過的東西,比方說某個方法或者是一些有趣的用法。比如說線程。沒錯,就是線程。或者確切說是Thread這個類。當我們在構建高可擴展性系統的時候,通常會面臨各種各樣的并發編程的問題,不過我們現在所要講的可能會略有不同。

從本文中你將會看到線程提供的一些不太常用的方法及技術。不管你是初學者還是高級用戶或者是Java專家,希望都能看一下哪些是你已經知道的,而哪些是剛了解的。如果你認為關于線程還有什么值得分享給大家的,希望能在下面積極回復。那我們就先開始吧。

初學者1.線程名

程序中的每個線程都有一個名字,創建線程的時候會給它分配一個簡單的Java字符串來作為線程名。默認的名字是”Thread-0″, “Thread-1″, “Thread-2″等等。現在有趣的事情來了——Thread提供了兩種方式來設置線程名:

線程構造函數,下面是最簡單的一個實現:

class SuchThread extends Thread { Public void run() {System.out.println ("Hi Mom! " + getName()); }}SuchThread wow = new SuchThread("much-name");線程名setter方法:

wow.setName(“Just another thread name”);

沒錯,線程名是可變的。因此我們可以在運行時修改它的名字,而不用在初始化的時候就指定好。name字段其實就是一個簡單的字符串對象。也就是說它能達到2³¹-1個字符那么長(Integer.MAX_VALUE)。這足夠用了。注意這個名字并不是一個唯一性的標識,因此不同的線程也可以擁有同樣的線程名。還有一點就是,不要把null用作線程名,否則會拋出異常(當然了,”null”還是可以的)。

使用線程名來調試問題

既然可以設置線程名,那么如果遵循一定的命名規則的話,出了問題的時候排查起來就能更容易一些。“Thread-6″這樣的名字看起來就太沒心沒肺了,肯定有比它更好的名字。在處理用戶請求的時候,可以將事務ID追加到線程名后面,這樣能顯著減少你排查問題的時間。

“pool-1-thread-1″ #17 prio=5 os_prio=31 tid=0x00007f9d620c9800nid=0x6d03 in Object.wait() [0x000000013ebcc000]

“pool-1-thread-1″,這也太嚴肅了吧。我們來看下這是什么情況,給它起一個好點的名字:

Thread.currentThread().setName(Context + TID + Params + current Time, ...);

現在我們再來運行下jstack,情況便豁然開朗了:

”Queue Processing Thread, MessageID: AB5CAD, type:AnalyzeGraph, queue: ACTIVE_PROD, Transaction_ID: 5678956,Start Time: 30/12/2014 17:37″ #17 prio=5 os_prio=31 tid=0x00007f9d620c9800nid=0x6d03 in Object.wait() [0x000000013ebcc000]

如果我們能知道線程在做什么,這樣當它出問題的時候,至少可以拿到事務ID來開始排查。你可以回溯這個問題,復現它,然后定位問題并搞定它。如果你想知道jstack有什么給力的用法,可以看下這篇文章。

2. 線程優先級

線程還有一個有意思的屬性就是它的優先級。線程的優先級介于1 (MINPRIORITY)到10 (MAXPRIORITY)之間,主線程默認是5(NORM_PRIORITY)。每個新線程都默認繼承父線程的優先級,因此如果你沒有設置過的話,所有線程的優先級都是5。這個是通常被忽視的屬性,我們可以通過getPriority()與setPriority()方法來獲取及修改它的值。線程的構造函數里是沒有這個功能的。

什么地方會用到優先級?

當然并不是所有的線程都是平等的,有的線程需要立即引起CPU的重視,而有些線程則只是后臺任務而已。優先級就是用來把這些告訴給操作系統的線程調度器的。在Takipi中,這是我們開發的一錯誤跟蹤及排查的工具,負責處理用戶異常的線程的優先級是MAX_PRIORITY,而那些只是在上報新的部署情況的線程,它們的優先級就要低一些。你可能會覺得優先級高的線程從JVM的線程調度器那得到的時間會多一些。但其實并都是這樣的。

在操作系統層面,每一個新線程都會對應一個本地線程,你所設置的Java線程的優先級會被轉化成本地線程的優先級,這個在各個平臺上是不一樣的。在Linux上,你可以打開“-XX:+UseThreadPriorities”選項來啟用這項功能。正如前面所說的,線程優先級只是你所提供的一個建議。和Linux本地的優先級相比,Java線程的優先級并不能覆蓋全所有的級別(Linux共有1到99個優先級,線程的優先級在是-20到20之間)。最大的好處就是你所設定的優先級能在每個線程獲得的CPU時間上有所體現,不過完全依賴于線程優先級的做法是不推薦的。

Java線程的5個使用技巧

進階篇3.線程本地存儲

這個和前面提到的兩個略有不同。ThreadLocal是在Thread類之外實現的一個功能(java.lang.ThreadLocal),但它會為每個線程分別存儲一份唯一的數據。正如它的名字所說的,它為線程提供了本地存儲,也就是說你所創建出來變量對每個線程實例來說都是唯一的。和線程名,線程優先級類似,你可以自定義出一些屬性,就好像它們是存儲在Thread線程內部一樣,是不是覺得酷?不過先別高興得太早了,有幾句丑話得先說在前頭。

創建ThreadLocal有兩種推薦方式:要么是靜態變量,要么是單例實例中的屬性,這樣可以是非靜態的。注意,它的作用域是全局的,只不過對訪問它的線程而言好像是本地的而已。在下面這個例子中,ThreadLocal里面存儲了一個數據結構,這樣我們可以很容易地訪問到它:

public static class CriticalData{ public int transactionId; public int username;}public static final ThreadLocal<CriticalData> globalData = new ThreadLocal<CriticalData>();

一旦獲取到了ThreadLocal對象,就可以通過 globalData.set()和globalData.get()方法來對它進行操作了。

全局變量?這不是什么好事

也盡然。ThreadLocal可以用來存儲事務ID。如果代碼中出現未捕獲異常的時候它就相當有用了。最佳實踐是設置一個UncaughtExceptionHandler,這個是Thread類本身就支持的,但是你得自己去實現一下這個接口。一旦執行到了UncaughtExceptionHandler里,就幾乎沒有任何線索能夠知道到底發生了什么事情了。這會兒你能獲取到的就只有Thread對象,之前導致異常發生的所有變量都無法再訪問了,因為那些棧幀都已經被彈出了。一旦到了UncaughtExceptionHandler里,這個線程就只剩下最后一口氣了,唯一能抓住的最后一根稻草就是ThreadLocal。

我們來試下這么做:

System.err.println("Transaction ID " + globalData.get().transactionId);

我們可以將一些與錯誤相關的有價值的上下文信息給存儲到里面添。ThreadLocal還有一個更有創意的用法,就是用它來分配一塊特定的內存,這樣工作線程可以把它當作緩存來不停地使用。當然了,這有沒有用得看你在CPU和內存之間是怎么權衡的了。沒錯,ThreadLocal需要注意的就是會造成內存空間的浪費。只要線程還活著,那么它就會一直存在,除非你主動釋放否則它是不會被回收的。因此如果使用它的話你最好注意一下,盡量保持簡單。

4. 用戶線程及守護線程

我們再回到Thread類。程序中的每個線程都會有一個狀態,要么是用戶狀態,要么是守護狀態。換句話說,要么是前臺線程要么是后臺線程。主線程默認是用戶線程,每個新線程都會從創建它的線程中繼承線程狀態。因此如果你把一個線程設置成守護線程,那么它所創建的所有線程都會被標記成守護線程。如果程序中的所有線程都是守護線程的話,那么這個進程便會終止。我們可以通過Boolean .setDaemon(true)和.isDaemon()方法來查看及設置線程狀態。

  什么時候會用到守護線程?

如果進程不必等到某個線程結束才能終止,那么這個線程就可以設置成守護線程。這省掉了正常關閉線程的那些麻煩事,可以立即將線程結束掉。換個角度來說,如果一個正在執行某個操作的線程必須要正確地關閉掉否則就會出現不好的后果的話,那么這個線程就應該是用戶線程。通常都是些關鍵的事務,比方說,數據庫錄入或者更新,這些操作都是不能中斷的。

專家級5. 處理器親和性(Processor Affinity)

這里要講的會更靠近硬件,也就是說,當軟件遇上了硬件。處理器親和性使得你能夠將線程或者進程綁定到特定的CPU核上。這意味著只要是某個特定的線程,它就肯定只會在某個特定的CPU核上執行。通常來講如何綁定是由操作系統的線程調度器根據它自己的邏輯來決定的,它很可能會將我們前面提到的線程優先級也一并考慮進來。

這么做的好處在于CPU緩存。如果某個線程只會在某個核上運行,那么它的數據恰好在緩存里的概率就大大提高了。如果數據正好就在CPU緩存里,那么就沒有必要重新再從內存里加載了。你所節省的這幾毫秒時間就能用在刀刃上,在這段時間里代碼可以馬上開始執行,也就能更好地利用所分配給它的CPU時間。當然了,操作系統層面可能會存在某種優化,硬件架構當然也是個很重要的因素,但利用了處理器的親和性至少能夠減小線程切換CPU的機率。

由于這里摻雜著多種因素,處理器親和性到底對吞吐量有多大的影響,最好還是通過測試的方式來進行證明。也許這個方法并不是總能顯著地提升性能,但至少有一個好處就是吞吐量會相對穩定。親和策略可以細化到非常細的粒度上,這取決于你具體想要什么。高頻交易行業便是這一策略最能大顯身手的場景之一。

處理器親和性的測試

Java對處理器的親和性并沒有原生的支持,當然了,故事也還沒有就此結束。在Linux上,我們可以通過taskset命令來設置進程的親和性。假設我們現在有一個Java進程在運行,而我們希望將它綁定到某個特定的CPU上:

taskset -c 1 “java AboutToBePinned”

如果是一個已經在運行了的進程:

taskset -c 1 <PID>

要想深入到線程級別還得再加些代碼才行。所幸的是,有一個開源庫能完成這樣的功能:Java-Thread-Affinity。這個庫是由OpenHFT的Peter Lawrey開發的,實現這一功能最簡單直接的方式應該就是使用這個庫了。我們通過一個例子來快速看下如何綁定某個線程,關于該庫的更多細節請參考它在Github上的文檔:

AffinityLock al = AffinityLock.acquireLock();

這樣就可以了。關于獲取鎖的一些更高級的選項——比如說根據不同的策略來選擇CPU——在Github上都有詳細的說明。

結論

本文我們介紹了關于線程的5點知識:線程名,線程本地存儲,優先級,守護線程以及處理器親和性。希望這能為你日常工作中所用到的內容打開一扇新的窗戶,期待你們的反饋!還有什么有關線程處理的方法可以分享給大家的嗎,請不吝賜教。

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲综合日韩| 国产精品一区二区精品| 国产情侣一区| 国产精品中文| 国产精品va| 国产精品宾馆| 国产a亚洲精品| 久久青青视频| 久久99精品久久久久久园产越南| 国产高清日韩| 亚洲成人二区| 日韩毛片网站| 国产精品久久久久久久免费观看| 欧美成a人免费观看久久| 欧美精品一区二区三区精品| 亚洲一区观看| 国产精品v日韩精品v欧美精品网站 | 亚洲一区二区三区久久久| 国产一区白浆| 欧美亚洲tv| 日韩在线观看不卡| 欧美日韩尤物久久| 亚洲精品进入| 日韩三区免费| 日韩av在线免费观看不卡| 高清久久一区| 亚洲精品无播放器在线播放| 久久精品九色| 亚洲综合福利| 成人免费电影网址| 国产日韩欧美一区二区三区在线观看| 欧美日韩国产观看视频| 亚洲aa在线| 欧美三级网址| 国产精品一级| 美女精品在线| 久久亚洲人体| 欧美欧美黄在线二区| 成人av二区| 国产精品字幕| 国产精东传媒成人av电影| 久久午夜影视| 欧美午夜精彩| 日韩在线高清| 麻豆91在线播放| 日韩高清三区| 99国产精品99久久久久久粉嫩| 黄色网一区二区| 欧美精品国产白浆久久久久| 亚洲欧美日韩高清在线| 日韩av在线播放网址| 亚洲精品黄色| 亚洲精品激情| 亚洲天堂av资源在线观看| 久久人人88| 神马午夜久久| 国产中文字幕一区二区三区| 国产伦精品一区二区三区视频| 免费人成黄页网站在线一区二区 | 欧美永久精品| 日韩久久99| 日韩美女精品| 青草国产精品| 国产精品最新自拍| 麻豆国产91在线播放| 日韩av不卡一区二区| 欧美一区网站| 精品国产精品久久一区免费式| 麻豆视频观看网址久久| 电影91久久久| 久久久五月天| 亚洲综合二区| 亚洲精品激情| 大香伊人久久精品一区二区 | 国产手机视频一区二区| 性色一区二区| 日欧美一区二区| 蜜桃视频一区二区三区在线观看| 在线免费观看亚洲| 国产精品一区二区三区四区在线观看 | 日韩av网站免费在线| 麻豆一区二区三| 亚洲二区视频| 日韩精品亚洲一区二区三区免费| 麻豆免费精品视频| 国产精品成人a在线观看| 国模 一区 二区 三区| 日本不卡不码高清免费观看| 日韩av有码| 亚洲精品高潮| 国产精品伦理久久久久久| 久久国产66| 国产成人精品一区二区三区视频 | 亚洲精品三级| 日韩精品1区| 蜜臀久久99精品久久久画质超高清| 欧美久久精品| 亚洲综合国产| 日韩欧美一区二区三区在线视频 | 婷婷激情一区| 91精品美女| 亚洲精品1区| 欧美黄色精品| 亚洲精品一级| 99精品在线观看| 国产激情精品一区二区三区| 尹人成人综合网| 动漫av一区| 亚洲精品国模| 亚洲黄色在线| 成人午夜精品| 成人在线视频区| 国产精品对白| 国产色噜噜噜91在线精品| 国产亚洲在线观看| 精品一区在线| 亚洲www免费| 高清av一区| 成人一二三区| 国产成人77亚洲精品www| 久久av免费| 久久男人av| 国产精品高清一区二区| 免费日韩视频| 亚洲深夜影院| 久久国产99| 久久国产精品久久w女人spa| 一区二区视频欧美| 亚洲综合另类| 日本免费在线视频不卡一不卡二| 蜜臀久久久99精品久久久久久| 亚洲欧美久久久| 日韩中文字幕不卡| 一本一道久久a久久| 亚洲精品一级| 欧美激情福利| 日韩精品第一区| 国产一区二区三区自拍| 久久久久.com| 国产视频一区欧美| 日韩精品导航| 欧美激情视频一区二区三区免费 | 中文字幕一区二区三区日韩精品| 免费看黄色91| 久久国际精品| 中文字幕人成乱码在线观看| 久久蜜桃精品| 黄色精品网站| 911精品国产| 欧产日产国产精品视频| 午夜影院欧美| 国产精品白丝一区二区三区| 国产精品不卡| 亚洲伊人精品酒店| 国产在线一区不卡| 中国女人久久久| 日韩国产91| 久久国产亚洲精品| 日韩福利在线观看| 99热精品久久| 国产欧美自拍一区| 亚洲午夜91| 少妇精品在线| 欧美69视频| 国产一区二区三区日韩精品| 老牛国产精品一区的观看方式| 麻豆高清免费国产一区| 综合激情婷婷| 欧美搞黄网站| 激情久久一区二区| 欧美日韩午夜电影网| 性色av一区二区怡红| 日韩一区电影| 精品精品99| 国产精品伊人| 蜜桃av一区二区| 一区二区视频欧美| 国产高清亚洲| 国产精品久久亚洲不卡| 日本中文字幕一区二区视频| 亚洲深爱激情| 香蕉精品视频在线观看| 麻豆网站免费在线观看| 国产精品超碰| 欧美日韩中出| 日韩av二区在线播放| 亚洲日本欧美| 香蕉久久国产| 日韩影院免费视频| 日韩中文字幕av电影| 亚洲综合另类| 久久一二三区| 国产精品外国| 久久亚洲欧美| 日韩在线一区二区| 日韩在线卡一卡二| 亚洲毛片在线免费| 日本aⅴ免费视频一区二区三区| 日韩av一级片| 国产一区二区色噜噜|