ThreadLocal 详解
轉(zhuǎn)自:https://www.cnblogs.com/renyuanwei/p/9635235.html
什么是ThreadLocal
?
? ??根據(jù)JDK文檔中的解釋:ThreadLocal的作用是提供線程內(nèi)的局部變量,這種變量在多線程環(huán)境下訪問(wèn)時(shí)能夠保證各個(gè)線程里變量的獨(dú)立性。
? ? 從這里可以看出,引入ThreadLocal的初衷是為了提供線程內(nèi)的局部變量
?
ThreadLocal?不是一個(gè)線程,而是一個(gè)線程的本地化對(duì)象。當(dāng)某個(gè)變量在使用?ThreadLocal?進(jìn)行維護(hù)時(shí),ThreadLocal?為使用該變量的每個(gè)線程分配了一個(gè)獨(dú)立的變量副本。
每個(gè)線程可以自行操作自己對(duì)應(yīng)的變量副本,而不會(huì)影響其他線程的變量副本。
?
API 方法
ThreadLocal?的 API 提供了如下的 4 個(gè)方法。
1)protected T initialValue()
返回當(dāng)前線程的局部變量副本的變量初始值。
2)T get()
返回當(dāng)前線程的局部變量副本的變量值,如果此變量副本不存在,則通過(guò)?initialValue()?方法創(chuàng)建此副本并返回初始值。
3)void set(T value)
設(shè)置當(dāng)前線程的局部變量副本的變量值為指定值。
4)void remove()
刪除當(dāng)前線程的局部變量副本的變量值。
在實(shí)際使用中,我們一般都要重寫(xiě)?initialValue()?方法,設(shè)置一個(gè)特定的初始值。
關(guān)于initialValue的初始化。本人嘗試了多種方式:
| 1 2 3 4 5 6 7 8 | //new ThreadLocal方式:不推薦 ???????final?ThreadLocal<String> commandThreads =?new?ThreadLocal<String>() { ???????????@Override ???????????protected?String initialValue() { ???????????????return?"execute :"+System.currentTimeMillis(); ???????????} ???????}; ???????System.out.println(commandThreads.get()); |
| 1 2 3 4 5 | //withInitial方式: ????????ThreadLocal<String> commandThreadnew = //???????????? ThreadLocal.withInitial(()-> "execute :"+System.currentTimeMillis()); ????????????????ThreadLocal.withInitial(()->new?String("execute :"+System.currentTimeMillis())); ????????System.out.println(commandThreadnew.get()); |
| 1 2 3 4 5 6 7 8 9 10 | //(new Supplier<String>(){}方式 推薦 ???????ThreadLocal<String> commandThreadnew1 = ???????????????ThreadLocal.withInitial(new?Supplier<String>() { ???????????????????@Override ???????????????????public?String get() { ???????????????????????return??"execute :"+System.currentTimeMillis(); ???????????????????} ???????????????}); ???????System.out.println(? commandThreadnew1.get()); |
?
以下是關(guān)于ThreadLocal 解決多線程變量共享問(wèn)題:
存在爭(zhēng)議點(diǎn):
ThreadLocal到底能不能解決共享對(duì)象的多線程訪問(wèn)問(wèn)題?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | package?com.wuxianjiezh.demo.threadpool; public?class?MainTest { ????public?static?void?main(String[] args) { ????????Bank bank =?new?Bank(); ????????Thread xMThread =?new?Thread(() -> bank.deposit(200),?"小明"); ????????Thread xGThread =?new?Thread(() -> bank.deposit(200),?"小剛"); ????????Thread xHThread =?new?Thread(() -> bank.deposit(200),?"小紅"); ????????xMThread.start(); ????????xGThread.start(); ????????xHThread.start(); ????} } class?Bank { ????private?int?money =?1000; ????public?void?deposit(int?money) { ????????String threadName = Thread.currentThread().getName(); ????????System.out.println(threadName +?"--當(dāng)前賬戶(hù)余額為:"?+?this.money); ????????this.money += money; ????????System.out.println(threadName +?"--存入 "?+ money +?" 后賬戶(hù)余額為:"?+?this.money); ????????try?{ ????????????Thread.sleep(1000); ????????}?catch?(InterruptedException e) { ????????????e.printStackTrace(); ????????} ????} } |
運(yùn)行結(jié)果:存在多線程輸出結(jié)果混亂
| 1 2 3 4 5 6 | 小明--當(dāng)前賬戶(hù)余額為:1000 小紅--當(dāng)前賬戶(hù)余額為:1000 小紅--存入?200?后賬戶(hù)余額為:1400 小剛--當(dāng)前賬戶(hù)余額為:1000 小剛--存入?200?后賬戶(hù)余額為:1600 小明--存入?200?后賬戶(hù)余額為:1200 |
使用?ThreadLocal?保存對(duì)象的局部變量。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public?class?MainTest { ????public?static?void?main(String[] args) { ????????Bank bank =?new?Bank(); ????????Thread xMThread =?new?Thread(() -> bank.deposit(200),?"小明"); ????????Thread xGThread =?new?Thread(() -> bank.deposit(200),?"小剛"); ????????Thread xHThread =?new?Thread(() -> bank.deposit(200),?"小紅"); ????????xMThread.start(); ????????xGThread.start(); ????????xHThread.start(); ????} } class?Bank { ????// 初始化賬戶(hù)余額為 100 ????ThreadLocal<Integer> account = ThreadLocal.withInitial(new?Supplier<Integer>() { ????????@Override ????????public?Integer get() { ????????????return?1000; ????????} ????}); ????public?void?deposit(int?money) { ????????String threadName = Thread.currentThread().getName(); ????????System.out.println(threadName +?"--當(dāng)前賬戶(hù)余額為:"?+ account.get()); ????????account.set(account.get() + money); ????????System.out.println(threadName +?"--存入 "?+ money +?" 后賬戶(hù)余額為:"?+ account.get()); ????????try?{ ????????????Thread.sleep(1000); ????????}?catch?(InterruptedException e) { ????????????e.printStackTrace(); ????????} ????} } |
運(yùn)行結(jié)果為:
| 1 2 3 4 5 6 7 | 小明--當(dāng)前賬戶(hù)余額為:1000 小紅--當(dāng)前賬戶(hù)余額為:1000 小紅--存入?200?后賬戶(hù)余額為:1200 小剛--當(dāng)前賬戶(hù)余額為:1000 小剛--存入?200?后賬戶(hù)余額為:1200 小明--存入?200?后賬戶(hù)余額為:1200 可以看到,我們要的效果達(dá)到了。各線程間同時(shí)操作自己的變量,相互間沒(méi)有影響。 |
ThreadLocal 與 Thread 同步機(jī)制的比較
-
同步機(jī)制采用了以時(shí)間換空間方式,通過(guò)對(duì)象鎖保證在同一個(gè)時(shí)間,對(duì)于同一個(gè)實(shí)例對(duì)象,只有一個(gè)線程訪問(wèn)。
-
ThreadLocal?采用以空間換時(shí)間方式,為每一個(gè)線程都提供一份變量,各線程間同時(shí)訪問(wèn)互不影響。
轉(zhuǎn)載于:https://www.cnblogs.com/sharpest/p/10884823.html
總結(jié)
以上是生活随笔為你收集整理的ThreadLocal 详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 团队开发流程总结
- 下一篇: Dubbo线程模型和调度策略