摘要:本人郵箱歡迎轉(zhuǎn)載轉(zhuǎn)載請注明網(wǎng)址代碼已經(jīng)全部托管有需要的同學(xué)自行下載引言之前我們講到都是多線程共享數(shù)據(jù)那么有沒有某一個(gè)共享的變量在這變量里面每個(gè)線程都能擁有自己的屬性呢比如說去旅店開房休息那么這個(gè)旅店就是一個(gè)共享的數(shù)據(jù)但是每個(gè)人開的房間是不一
引言本人郵箱:
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明網(wǎng)址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經(jīng)全部托管github有需要的同學(xué)自行下載
之前我們講到都是多線程共享數(shù)據(jù).那么有沒有某一個(gè)共享的變量,在這變量里面,每個(gè)線程都能擁有自己的屬性呢?比如說,去旅店開房休息.那么這個(gè)旅店就是一個(gè)共享的數(shù)據(jù),但是每個(gè)人開的房間是不一樣的.這個(gè)要怎么做呢?這里我先試著寫一些
例子1讓我們編寫一個(gè)程序,主線程開啟十個(gè)子線程,然后每個(gè)子線程都做1~100的累加,都是共享同一個(gè)List
public class TestMain { public static class CalcRunnable implements Runnable{ Listlist ; int index; public CalcRunnable(List list, int index) { this.list = list; this.index = index; } @Override public void run() { for (int i = 1; i <= 100; i++){ list.set(index, list.get(index) + i); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { List list = new ArrayList<>(); List threads = new ArrayList<>(); for (int i = 0; i < 10; i ++){ list.add(0); threads.add(new Thread(new CalcRunnable(list,i))); } for (Thread thread : threads){ thread.start(); } try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list); } }
輸出結(jié)果為
[5050, 5050, 5050, 5050, 5050, 5050, 5050, 5050, 5050, 5050]
例子2這里每個(gè)線程都共享了list,但是也沒有使用關(guān)鍵字synchronized進(jìn)行同步,為什么結(jié)果還是正確的呢?原因很簡單,那就是每個(gè)線程都使用固定的索引進(jìn)行計(jì)算,互不干擾.所以結(jié)果不會(huì)受其他線程影響的.
現(xiàn)在把上面的例子中的List
public class TestMain1 { public static class CalcRunnable implements Runnable{ Mapmap; public CalcRunnable(Map map) { this.map = map; } @Override public void run() { Thread self = Thread.currentThread(); for (int i = 1; i <= 100; i++){ map.put(self, map.get(self) + i); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Map map = new HashMap<>(); List threads = new ArrayList<>(); for (int i = 0; i < 10; i ++){ Thread thread = new Thread(new CalcRunnable(map)); map.put(thread,0); threads.add(thread); } for (Thread thread : threads){ thread.start(); } try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(map); } }
運(yùn)行結(jié)果
{Thread[Thread-1,5,]=5050, Thread[Thread-3,5,]=5050, Thread[Thread-6,5,]=5050, Thread[Thread-0,5,]=5050, Thread[Thread-8,5,]=5050, Thread[Thread-5,5,]=5050, Thread[Thread-7,5,]=5050, Thread[Thread-2,5,]=5050, Thread[Thread-4,5,]=5050, Thread[Thread-9,5,]=5050}
例子3結(jié)果也是完全正確,道理跟上面的例子一樣,每個(gè)線程雖然共用同一個(gè)數(shù)據(jù)map,但實(shí)際上每個(gè)線程都是用map中特定的那個(gè)元素
其實(shí)用map還有一種更簡單的方式,那就是今天要講的ThreadLocal,不廢話,看例子
public class TestMain3 { public static class CalcRunnable implements Runnable{ ThreadLocalthreadLocal; public CalcRunnable(ThreadLocal threadLocal) { this.threadLocal = threadLocal; } @Override public void run() { threadLocal.set(0);//設(shè)置默認(rèn)值 for (int i = 1; i <= 100; i++){ threadLocal.set(threadLocal.get() + i); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 的計(jì)算結(jié)果為: " + threadLocal.get()); } } public static void main(String[] args) { ThreadLocal threadLocal = new ThreadLocal<>(); List threads = new ArrayList<>(); for (int i = 0; i < 10; i ++){ Thread thread = new Thread(new CalcRunnable(threadLocal)); threads.add(thread); } for (Thread thread : threads){ thread.start(); } } }
運(yùn)行結(jié)果
Thread-0 的計(jì)算結(jié)果為: 5050 Thread-5 的計(jì)算結(jié)果為: 5050 Thread-1 的計(jì)算結(jié)果為: 5050 Thread-4 的計(jì)算結(jié)果為: 5050 Thread-7 的計(jì)算結(jié)果為: 5050 Thread-6 的計(jì)算結(jié)果為: 5050 Thread-3 的計(jì)算結(jié)果為: 5050 Thread-2 的計(jì)算結(jié)果為: 5050 Thread-8 的計(jì)算結(jié)果為: 5050 Thread-9 的計(jì)算結(jié)果為: 5050
總結(jié)原理,其實(shí)就是跟例子2的Map
,在ThreadLocal中實(shí)現(xiàn)了一個(gè)ThreadLocalMap內(nèi)部類,然后在調(diào)用ThreadLocal.get和ThreadLocal.set的時(shí)候,其實(shí)要獲取當(dāng)前線程去做相應(yīng)的操作.
如果以后大家想讓多線程共享一個(gè)變量,但又不想互相影響的時(shí)候,那么首選ThreadLocal.因?yàn)閷Ρ壬厦嫒齻€(gè)例子,發(fā)現(xiàn)使用ThreadLocal是最簡單的,而且不容易出錯(cuò)的.比如在web開發(fā)中,可以在多線程中存放session,或者數(shù)據(jù)庫連接池的時(shí)候,也可以使用ThreadLocal在存放數(shù)據(jù)庫連接.
打賞如果覺得我的文章寫的還過得去的話,有錢就捧個(gè)錢場,沒錢給我捧個(gè)人場(幫我點(diǎn)贊或推薦一下)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/67042.html
摘要:前言本篇主要講解如何去優(yōu)化鎖機(jī)制或者克服多線程因?yàn)殒i可導(dǎo)致性能下降的問題線程變量有這樣一個(gè)場景,前面是一大桶水,個(gè)人去喝水,為了保證線程安全,我們要在杯子上加鎖導(dǎo)致大家輪著排隊(duì)喝水,因?yàn)榧恿随i的杯子是同步的,只能有一個(gè)人拿著這個(gè)唯一的杯子喝 前言 本篇主要講解如何去優(yōu)化鎖機(jī)制或者克服多線程因?yàn)殒i可導(dǎo)致性能下降的問題 ThreadLocal線程變量 有這樣一個(gè)場景,前面是一大桶水,10個(gè)...
摘要:注意,和都是隨機(jī)選擇一個(gè)線程,解除其阻塞狀態(tài),可能會(huì)造成死鎖。生產(chǎn)者線程向隊(duì)列插入元素,消費(fèi)者線程從隊(duì)列取出元素。當(dāng)添加時(shí)隊(duì)列已滿或取出時(shí)隊(duì)列為空,阻塞隊(duì)列導(dǎo)致線程阻塞。里面有個(gè)小技巧,一個(gè)線程搜索完畢時(shí)向阻塞隊(duì)列填充,讓所有線程能停下來。 多線程對共享數(shù)據(jù)的讀寫涉及到同步問題,鎖和條件是線程同步的強(qiáng)大工具。鎖用來保護(hù)代碼片段(臨界區(qū)),任何時(shí)刻只能有一個(gè)線程執(zhí)行被保護(hù)的代碼。條件對象...
摘要:下面是線程相關(guān)的熱門面試題,你可以用它來好好準(zhǔn)備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應(yīng)該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗(yàn)及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個(gè)重要的特點(diǎn)就是內(nèi)置了對并發(fā)的支持,讓Java大受企業(yè)和程序員...
摘要:并沒有提供語言級的線程局部變量,而是在類庫里提供了線程局部變量的功能,也就是這次的主角類。 Yuicon 轉(zhuǎn)載請注明原創(chuàng)出處,謝謝! 序 在多線程環(huán)境下,訪問非線程安全的變量時(shí)必須進(jìn)行線程同步,例如使用synchronized方式訪問HashMap實(shí)例。但是同步訪問會(huì)降低并發(fā)性,影響系統(tǒng)性能。這時(shí)候就可以用空間換時(shí)間,如果我們給每個(gè)線程都分配一個(gè)獨(dú)立的變量,就可以用非同步的方式使用非...
摘要:方法,刪除當(dāng)前線程綁定的這個(gè)副本數(shù)字,這個(gè)值是的值,普通的是使用鏈表來處理沖突的,但是是使用線性探測法來處理沖突的,就是每次增加的步長,根據(jù)參考資料所說,選擇這個(gè)數(shù)字是為了讓沖突概率最小。 showImg(https://segmentfault.com/img/remote/1460000019828633); 老套路,先列舉下關(guān)于ThreadLocal常見的疑問,希望可以通過這篇學(xué)...
閱讀 1365·2021-11-23 09:51
閱讀 3530·2021-09-06 15:00
閱讀 1049·2021-08-16 10:57
閱讀 1433·2019-08-30 12:46
閱讀 989·2019-08-29 12:22
閱讀 1671·2019-08-29 11:07
閱讀 3203·2019-08-26 11:23
閱讀 3044·2019-08-23 15:14