欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
輕松使用線(xiàn)程: 不共享有時(shí)是最好的
利用ThreadLocal 提高可伸縮性

ThreadLocal 類(lèi)是悄悄地出現在 Java 平臺版本 1.2 中的。雖然支持線(xiàn)程局部變量早就是許多線(xiàn)程工具(例如 Posix pthreads 工具)的一部分,但 Java Threads API 的最初設計卻沒(méi)有這項有用的功能。而且,最初的實(shí)現也相當低效。由于這些原因,ThreadLocal 極少受到關(guān)注,但對簡(jiǎn)化線(xiàn)程安全并發(fā)程序的開(kāi)發(fā)來(lái)說(shuō),它卻是很方便的。在輕松使用線(xiàn)程的第 3 部分,Java 軟件顧問(wèn) Brian Goetz 研究了 ThreadLocal 并提供了一些使用技巧。
參加 Brian 的多線(xiàn)程 Java 編程討論論壇以獲得您工程中的線(xiàn)程和并發(fā)問(wèn)題的幫助。

編寫(xiě)線(xiàn)程安全類(lèi)是困難的。它不但要求仔細分析在什么條件可以對變量進(jìn)行讀寫(xiě),而且要求仔細分析其它類(lèi)能如何使用某個(gè)類(lèi)。有時(shí),要在不影響類(lèi)的功能、易用性或性能的情況下使類(lèi)成為線(xiàn)程安全的是很困難的。有些類(lèi)保留從一個(gè)方法調用到下一個(gè)方法調用的狀態(tài)信息,要在實(shí)踐中使這樣的類(lèi)成為線(xiàn)程安全的是困難的。

管理非線(xiàn)程安全類(lèi)的使用比試圖使類(lèi)成為線(xiàn)程安全的要更容易些。非線(xiàn)程安全類(lèi)通??梢园踩卦诙嗑€(xiàn)程程序中使用,只要您能確保一個(gè)線(xiàn)程所用的類(lèi)的實(shí)例不被其它線(xiàn)程使用。例如,JDBC Connection 類(lèi)是非線(xiàn)程安全的 — 兩個(gè)線(xiàn)程不能在小粒度級上安全地共享一個(gè) Connection — 但如果每個(gè)線(xiàn)程都有它自己的 Connection,那么多個(gè)線(xiàn)程就可以同時(shí)安全地進(jìn)行數據庫操作。

不使用 ThreadLocal 為每個(gè)線(xiàn)程維護一個(gè)單獨的 JDBC 連接(或任何其它對象)當然是可能的;Thread API 給了我們把對象和線(xiàn)程聯(lián)系起來(lái)所需的所有工具。而 ThreadLocal 則使我們能更容易地把線(xiàn)程和它的每線(xiàn)程(per-thread)數據成功地聯(lián)系起來(lái)。

什么是線(xiàn)程局部變量(thread-local variable)?
線(xiàn)程局部變量高效地為每個(gè)使用它的線(xiàn)程提供單獨的線(xiàn)程局部變量值的副本。每個(gè)線(xiàn)程只能看到與自己相聯(lián)系的值,而不知道別的線(xiàn)程可能正在使用或修改它們自己的副本。一些編譯器(例如 Microsoft Visual C++ 編譯器或 IBM XL FORTRAN 編譯器)用存儲類(lèi)別修飾符(像 static 或 volatile)把對線(xiàn)程局部變量的支持集成到了其語(yǔ)言中。Java 編譯器對線(xiàn)程局部變量不提供特別的語(yǔ)言支持;相反地,它用 ThreadLocal 類(lèi)實(shí)現這些支持,核心 Thread 類(lèi)中有這個(gè)類(lèi)的特別支持。

因為線(xiàn)程局部變量是通過(guò)一個(gè)類(lèi)來(lái)實(shí)現的,而不是作為 Java 語(yǔ)言本身的一部分,所以 Java 語(yǔ)言線(xiàn)程局部變量的使用語(yǔ)法比內建線(xiàn)程局部變量語(yǔ)言的使用語(yǔ)法要笨拙一些。要創(chuàng )建一個(gè)線(xiàn)程局部變量,請實(shí)例化類(lèi) ThreadLocal 的一個(gè)對象。 ThreadLocal 類(lèi)的行為與 java.lang.ref 中的各種 Reference 類(lèi)的行為很相似;ThreadLocal 類(lèi)充當存儲或檢索一個(gè)值時(shí)的間接句柄。清單 1 顯示了 ThreadLocal 接口。

清單 1. ThreadLocal 接口
public class ThreadLocal {
public Object get();
public void set(Object newValue);
public Object initialValue();
}


get() 訪(fǎng)問(wèn)器檢索變量的當前線(xiàn)程的值;set() 訪(fǎng)問(wèn)器修改當前線(xiàn)程的值。initialValue() 方法是可選的,如果線(xiàn)程未使用過(guò)某個(gè)變量,那么您可以用這個(gè)方法來(lái)設置這個(gè)變量的初始值;它允許延遲初始化。用一個(gè)示例實(shí)現來(lái)說(shuō)明 ThreadLocal 的工作方式是最好的方法。清單 2 顯示了 ThreadLocal 的一個(gè)實(shí)現方式。它不是一個(gè)特別好的實(shí)現(雖然它與最初實(shí)現非常相似),所以很可能性能不佳,但它清楚地說(shuō)明了 ThreadLocal 的工作方式。

清單 2. ThreadLocal 的糟糕實(shí)現

public class ThreadLocal {
private Map values = Collections.synchronizedMap(new HashMap());

public Object get() {
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread)) {
o = initialValue();
values.put(curThread, o);
}
return o;
}

public void set(Object newValue) {
values.put(Thread.currentThread(), newValue);
}

public Object initialValue() {
return null;
}
}



這個(gè)實(shí)現的性能不會(huì )很好,因為每個(gè) get() 和 set() 操作都需要 values 映射表上的同步,而且如果多個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)同一個(gè) ThreadLocal,那么將發(fā)生爭用。此外,這個(gè)實(shí)現也是不切實(shí)際的,因為用 Thread 對象做 values 映射表中的關(guān)鍵字將導致無(wú)法在線(xiàn)程退出后對 Thread 進(jìn)行垃圾回收,而且也無(wú)法對死線(xiàn)程的 ThreadLocal 的特定于線(xiàn)程的值進(jìn)行垃圾回收。

用 ThreadLocal 實(shí)現每線(xiàn)程 Singleton
線(xiàn)程局部變量常被用來(lái)描繪有狀態(tài)“單子”(Singleton) 或線(xiàn)程安全的共享對象,或者是通過(guò)把不安全的整個(gè)變量封裝進(jìn) ThreadLocal,或者是通過(guò)把對象的特定于線(xiàn)程的狀態(tài)封裝進(jìn) ThreadLocal。例如,在與數據庫有緊密聯(lián)系的應用程序中,程序的很多方法可能都需要訪(fǎng)問(wèn)數據庫。在系統的每個(gè)方法中都包含一個(gè) Connection 作為參數是不方便的 — 用“單子”來(lái)訪(fǎng)問(wèn)連接可能是一個(gè)雖然更粗糙,但卻方便得多的技術(shù)。然而,多個(gè)線(xiàn)程不能安全地共享一個(gè) JDBC Connection。如清單 3 所示,通過(guò)使用“單子”中的 ThreadLocal,我們就能讓我們的程序中的任何類(lèi)容易地獲取每線(xiàn)程 Connection 的一個(gè)引用。這樣,我們可以認為 ThreadLocal 允許我們創(chuàng )建每線(xiàn)程單子。

清單 3. 把一個(gè) JDBC 連接存儲到一個(gè)每線(xiàn)程 Singleton 中
public class ConnectionDispenser {
private static class ThreadLocalConnection extends ThreadLocal {
public Object initialValue() {
return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
}
}

private ThreadLocalConnection conn = new ThreadLocalConnection();

public static Connection getConnection() {
return (Connection) conn.get();
}
}




任何創(chuàng )建的花費比使用的花費相對昂貴些的有狀態(tài)或非線(xiàn)程安全的對象,例如 JDBC Connection 或正則表達式匹配器,都是可以使用每線(xiàn)程單子(singleton)技術(shù)的好地方。當然,在類(lèi)似這樣的地方,您可以使用其它技術(shù),例如用池,來(lái)安全地管理共享訪(fǎng)問(wèn)。然而,從可伸縮性角度看,即使是用池也存在一些潛在缺陷。因為池實(shí)現必須使用同步,以維護池數據結構的完整性,如果所有線(xiàn)程使用同一個(gè)池,那么在有很多線(xiàn)程頻繁地對池進(jìn)行訪(fǎng)問(wèn)的系統中,程序性能將因爭用而降低。

用 ThreadLocal 簡(jiǎn)化調試日志紀錄
其它適合使用 ThreadLocal 但用池卻不能成為很好的替代技術(shù)的應用程序包括存儲或累積每線(xiàn)程上下文信息以備稍后檢索之用這樣的應用程序。例如,假設您想創(chuàng )建一個(gè)用于管理多線(xiàn)程應用程序調試信息的工具。您可以用如清單 4 所示的 DebugLogger 類(lèi)作為線(xiàn)程局部容器來(lái)累積調試信息。在一個(gè)工作單元的開(kāi)頭,您清空容器,而當一個(gè)錯誤出現時(shí),您查詢(xún)該容器以檢索這個(gè)工作單元迄今為止生成的所有調試信息。

清單 4. 用 ThreadLocal 管理每線(xiàn)程調試日志
public class DebugLogger {
private static class ThreadLocalList extends ThreadLocal {
public Object initialValue() {
return new ArrayList();
}

public List getList() {
return (List) super.get();
}
}

private ThreadLocalList list = new ThreadLocalList();
private static String[] stringArray = new String[0];

public void clear() {
list.getList().clear();
}

public void put(String text) {
list.getList().add(text);
}

public String[] get() {
return list.getList().toArray(stringArray);
}
}





在您的代碼中,您可以調用 DebugLogger.put() 來(lái)保存您的程序正在做什么的信息,而且,稍后如果有必要(例如發(fā)生了一個(gè)錯誤),您能夠容易地檢索與某個(gè)特定線(xiàn)程相關(guān)的調試信息。 與簡(jiǎn)單地把所有信息轉儲到一個(gè)日志文件,然后努力找出哪個(gè)日志記錄來(lái)自哪個(gè)線(xiàn)程(還要擔心線(xiàn)程爭用日志紀錄對象)相比,這種技術(shù)簡(jiǎn)便得多,也有效得多。

ThreadLocal 在基于 servlet 的應用程序或工作單元是一個(gè)整體請求的任何多線(xiàn)程應用程序服務(wù)器中也是很有用的,因為在處理請求的整個(gè)過(guò)程中將要用到單個(gè)線(xiàn)程。您可以通過(guò)前面講述的每線(xiàn)程單子技術(shù)用 ThreadLocal 變量來(lái)存儲各種每請求(per-request)上下文信息。

ThreadLocal 的線(xiàn)程安全性稍差的堂兄弟,InheritableThreadLocal
ThreadLocal 類(lèi)有一個(gè)親戚,InheritableThreadLocal,它以相似的方式工作,但適用于種類(lèi)完全不同的應用程序。創(chuàng )建一個(gè)線(xiàn)程時(shí)如果保存了所有 InheritableThreadLocal 對象的值,那么這些值也將自動(dòng)傳遞給子線(xiàn)程。如果一個(gè)子線(xiàn)程調用 InheritableThreadLocal 的 get(),那么它將與它的父線(xiàn)程看到同一個(gè)對象。為保護線(xiàn)程安全性,您應該只對不可變對象(一旦創(chuàng )建,其狀態(tài)就永遠不會(huì )被改變的對象)使用 InheritableThreadLocal,因為對象被多個(gè)線(xiàn)程共享。InheritableThreadLocal 很合適用于把數據從父線(xiàn)程傳到子線(xiàn)程,例如用戶(hù)標識(user id)或事務(wù)標識(transaction id),但不能是有狀態(tài)對象,例如 JDBC Connection。

ThreadLocal 的性能
雖然線(xiàn)程局部變量早已赫赫有名并被包括 Posix pthreads 規范在內的很多線(xiàn)程框架支持,但最初的 Java 線(xiàn)程設計中卻省略了它,只是在 Java 平臺的版本 1.2 中才添加上去。在很多方面,ThreadLocal 仍在發(fā)展之中;在版本 1.3 中它被重寫(xiě),版本 1.4 中又重寫(xiě)了一次,兩次都專(zhuān)門(mén)是為了性能問(wèn)題。

在 JDK 1.2 中,ThreadLocal 的實(shí)現方式與清單 2 中的方式非常相似,除了用同步 WeakHashMap 代替 HashMap 來(lái)存儲 values 之外。(以一些額外的性能開(kāi)銷(xiāo)為代價(jià),使用 WeakHashMap 解決了無(wú)法對 Thread 對象進(jìn)行垃圾回收的問(wèn)題。)不用說(shuō),ThreadLocal 的性能是相當差的。

Java 平臺版本 1.3 提供的 ThreadLocal 版本已經(jīng)盡量更好了;它不使用任何同步,從而不存在可伸縮性問(wèn)題,而且它也不使用弱引用。相反地,人們通過(guò)給 Thread 添加一個(gè)實(shí)例變量(該變量用于保存當前線(xiàn)程的從線(xiàn)程局部變量到它的值的映射的 HashMap)來(lái)修改 Thread 類(lèi)以支持 ThreadLocal。因為檢索或設置一個(gè)線(xiàn)程局部變量的過(guò)程不涉及對可能被另一個(gè)線(xiàn)程讀寫(xiě)的數據的讀寫(xiě)操作,所以您可以不用任何同步就實(shí)現 ThreadLocal.get() 和 set()。而且,因為每線(xiàn)程值的引用被存儲在自已的 Thread 對象中,所以當對 Thread 進(jìn)行垃圾回收時(shí),也能對該 Thread 的每線(xiàn)程值進(jìn)行垃圾回收。

不幸的是,即使有了這些改進(jìn),Java 1.3 中的 ThreadLocal 的性能仍然出奇地慢。據我的粗略測量,在雙處理器 Linux 系統上的 Sun 1.3 JDK 中進(jìn)行 ThreadLocal.get() 操作,所耗費的時(shí)間大約是無(wú)爭用同步的兩倍。性能這么差的原因是 Thread.currentThread() 方法的花費非常大,占了 ThreadLocal.get() 運行時(shí)間的三分之二還多。雖然有這些缺點(diǎn),JDK 1.3 ThreadLocal.get() 仍然比爭用同步快得多,所以如果在任何存在嚴重爭用的地方(可能是有非常多的線(xiàn)程,或者同步塊被頻繁地執行,或者同步塊很大),ThreadLocal 可能仍然要高效得多。

在 Java 平臺的最新版本,即版本 1.4b2 中,ThreadLocal 和 Thread.currentThread() 的性能都有了很大提高。有了這些提高,ThreadLocal 應該比其它技術(shù),如用池,更快。由于它比其它技術(shù)更簡(jiǎn)單,也更不易出錯,人們最終將發(fā)現它是避免線(xiàn)程間出現不希望的交互的有效途徑。

ThreadLocal 的好處
ThreadLocal 能帶來(lái)很多好處。它常常是把有狀態(tài)類(lèi)描繪成線(xiàn)程安全的,或者封裝非線(xiàn)程安全類(lèi)以使它們能夠在多線(xiàn)程環(huán)境中安全地使用的最容易的方式。使用 ThreadLocal 使我們可以繞過(guò)為實(shí)現線(xiàn)程安全而對何時(shí)需要同步進(jìn)行判斷的復雜過(guò)程,而且因為它不需要任何同步,所以也改善了可伸縮性。除簡(jiǎn)單之外,用 ThreadLocal 存儲每線(xiàn)程單子或每線(xiàn)程上下文信息在歸檔方面還有一個(gè)頗有價(jià)值好處 — 通過(guò)使用 ThreadLocal,存儲在 ThreadLocal 中的對象都是不被線(xiàn)程共享的是清晰的,從而簡(jiǎn)化了判斷一個(gè)類(lèi)是否線(xiàn)程安全的工作。

我希望您從這個(gè)系列中得到了樂(lè )趣,也學(xué)到了知識,我也鼓勵您到我的討論論壇中來(lái)深入研究多線(xiàn)程問(wèn)題。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java之ThreadLocal
java中ThreadLocal類(lèi)的使用
研究java.lang.ThreadLocal類(lèi)
ThreadLocal 那點(diǎn)事兒
理解ThreadLocal
Java線(xiàn)程(篇外篇):線(xiàn)程本地變量ThreadLocal
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久