生活随笔
收集整理的這篇文章主要介紹了
线程管理(九)使用本地线程变量
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
聲明:本文是《?Java 7 Concurrency Cookbook?》的第一章, 作者: Javier Fernández González 譯者:鄭玉婷 校對(duì):方騰飛
使用本地線程變量
并發(fā)應(yīng)用的一個(gè)關(guān)鍵地方就是共享數(shù)據(jù)。這個(gè)對(duì)那些擴(kuò)展Thread類(lèi)或者實(shí)現(xiàn)Runnable接口的對(duì)象特別重要。
如果你創(chuàng)建一個(gè)類(lèi)對(duì)象,實(shí)現(xiàn)Runnable接口,然后多個(gè)Thread對(duì)象使用同樣的Runnable對(duì)象,全部的線程都共享同樣的屬性。這意味著,如果你在一個(gè)線程里改變一個(gè)屬性,全部的線程都會(huì)受到這個(gè)改變的影響。
有時(shí),你希望程序里的各個(gè)線程的屬性不會(huì)被共享。 Java 并發(fā) API提供了一個(gè)很清楚的機(jī)制叫本地線程變量。
在這個(gè)指南中, 我們將開(kāi)發(fā)一個(gè)程序,這個(gè)程序用來(lái)描述在第一段話(huà)里的問(wèn)題,和另一個(gè)程序使用本地線程變量機(jī)制解決這個(gè)問(wèn)題。
準(zhǔn)備
指南中的例子是使用Eclipse IDE 來(lái)實(shí)現(xiàn)的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打開(kāi)并創(chuàng)建一個(gè)新的java項(xiàng)目。
怎么做呢…
按照這些步驟來(lái)實(shí)現(xiàn)下面的例子:
1.? ?首先,我們來(lái)實(shí)現(xiàn)一個(gè)程序含有上述的問(wèn)題。
創(chuàng)建一個(gè)類(lèi)名為 UnsafeTask 并實(shí)現(xiàn) Runnable 接口。 聲明一個(gè)?private?java.util.Date 屬性.
| 1 | public?class?UnsafeTask?implements?Runnable{ |
| 2 | private?Date startDate; |
2. 實(shí)現(xiàn)UnsafeTask 對(duì)象的run() 方法,此方法會(huì)初始 startDate 屬性, 把值寫(xiě)入控制臺(tái),隨機(jī)休眠一段時(shí)間,最后在寫(xiě)入startDate 屬性。
| 04 | System.out.printf("Starting Thread: %s : %s\n",Thread. currentThread().getId(),startDate); |
| 06 | TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10)); |
| 07 | }?catch?(InterruptedException e) { |
| 10 | System.out.printf("Thread Finished: %s : %s\n",Thread. currentThread().getId(),startDate); |
3.? ?現(xiàn)在,來(lái)實(shí)現(xiàn)這個(gè)有問(wèn)題例子的主類(lèi)。創(chuàng)建一個(gè) Main ?類(lèi)和 main() 方法. 此方法會(huì)創(chuàng)建一個(gè) UnsafeTask 類(lèi)的對(duì)象,并開(kāi)始3個(gè)線程使用這個(gè)對(duì)象,每個(gè)線程間休眠2秒。
| 02 | public?static?void?main(String[] args) { |
| 03 | UnsafeTask task=new?UnsafeTask(); |
| 04 | ?for?(int?i=0; i<10; i++){ |
| 05 | Thread thread=new?Thread(task); |
| 07 | try?{ TimeUnit.SECONDS.sleep(2); |
| 08 | }?catch?(InterruptedException e) { |
4.? ?在以下的裁圖,你可以發(fā)現(xiàn)這個(gè)程序的執(zhí)行結(jié)果。每個(gè)線程有著不同的開(kāi)始時(shí)間,但是全部都有相同的結(jié)束時(shí)間。
5.? ?如在之前提到的, 我們會(huì)使用本地線程變量機(jī)制來(lái)解決這個(gè)問(wèn)題。
6.? ?創(chuàng)建一個(gè)類(lèi)名為 SafeTask a一定實(shí)現(xiàn) Runnable 接口。
| 1 | public?class?SafeTask?implements?Runnable { |
7.?? 聲明 ThreadLocal<Date> 類(lèi)對(duì)象。此對(duì)象有隱含實(shí)現(xiàn)了 initialValue()方法. 此方法會(huì)返回真實(shí)日期。
| 1 | private?static?ThreadLocal<Date> startDate=?new?ThreadLocal<Date>() { |
| 2 | protected?Date initialValue(){ |
8.? ?實(shí)現(xiàn)run()方法。它和 UnsafeClass的run() 方法功能一樣,只是改變了屬性的訪問(wèn)方式。
| 03 | ??System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get()); |
| 05 | ??TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10)); |
| 06 | }?catch?(InterruptedException e) { |
| 09 | System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get()); |
9. ???這個(gè)例子的主類(lèi)跟不安全例子一樣,把名字改成 Runnable 類(lèi)。
10. 運(yùn)行例子并分析不同處。
它是怎么工作的…
在下面的截圖里,你可以看到線程安全模式下程序運(yùn)行的結(jié)果。現(xiàn)在3個(gè) Thread 對(duì)象都有他們自己的startDate 屬性值。看下圖:
本地線程變量為每個(gè)使用這些變量的線程儲(chǔ)存屬性值。可以用 get() 方法讀取值和使用 set() 方法改變值。 如果第一次你訪問(wèn)本地線程變量的值,如果沒(méi)有值給當(dāng)前的線程對(duì)象,那么本地線程變量會(huì)調(diào)用 initialValue() 方法來(lái)設(shè)置值給線程并返回初始值。
更多…
本地線程類(lèi)還提供 remove() 方法,刪除存儲(chǔ)在線程本地變量里的值。
Java 并發(fā) API 包括 InheritableThreadLocal 類(lèi)提供線程創(chuàng)建線程的值的遺傳性 。如果線程A有一個(gè)本地線程變量,然后它創(chuàng)建了另一個(gè)線程B,那么線程B將有與A相同的本地線程變量值。 你可以覆蓋 childValue() 方法來(lái)初始子線程的本地線程變量的值。 它接收父線程的本地線程變量作為參數(shù)。
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明:?轉(zhuǎn)載自并發(fā)編程網(wǎng) – ifeve.com本文鏈接地址:?線程管理(九)使用本地線程變量
文章轉(zhuǎn)自?并發(fā)編程網(wǎng)-ifeve.com
總結(jié)
以上是生活随笔為你收集整理的线程管理(九)使用本地线程变量的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。