X-Spirit
Always Beyond the Time
BlogJava
|
首頁(yè)
|
發(fā)新隨筆
|
發(fā)新文章
|
聯(lián)系
|
聚合
|
管理
隨筆:91 文章:1 評(píng)論:65 引用:0
Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
前面我們介紹了Java當(dāng)中多個(gè)線(xiàn)程搶占一個(gè)共享資源的問(wèn)題。但不論是同步還是重入鎖,都不能實(shí)實(shí)在在的解決資源緊缺的情況,這些方案只是靠制定規(guī)則來(lái)約束線(xiàn)程的行為,讓它們不再拼命的爭(zhēng)搶?zhuān)皇钦嬲龔膶?shí)質(zhì)上解決他們對(duì)資源的需求。
在JDK 1.2當(dāng)中,引入了java.lang.ThreadLocal。它為我們提供了一種全新的思路來(lái)解決線(xiàn)程并發(fā)的問(wèn)題。但是他的名字難免讓我們望文生義:本地線(xiàn)程?
什么是本地線(xiàn)程?
本地線(xiàn)程開(kāi)玩笑的說(shuō):不要迷戀哥,哥只是個(gè)傳說(shuō)。
其實(shí)ThreadLocal并非Thread at Local,而是LocalVariable in a Thread。
根據(jù)WikiPedia上的介紹,ThreadLocal其實(shí)是源于一項(xiàng)多線(xiàn)程技術(shù),叫做Thread Local Storage,即線(xiàn)程本地存儲(chǔ)技術(shù)。不僅僅是Java,在C++、C#、.NET、Python、Ruby、Perl等開(kāi)發(fā)平臺(tái)上,該技術(shù)都已經(jīng)得以實(shí)現(xiàn)。
當(dāng)使用ThreadLocal維護(hù)變量時(shí),它會(huì)為每個(gè)使用該變量的線(xiàn)程提供獨(dú)立的變量副本。也就是說(shuō),他從根本上解決的是資源數(shù)量的問(wèn)題,從而使得每個(gè)線(xiàn)程持有相對(duì)獨(dú)立的資源。這樣,當(dāng)多個(gè)線(xiàn)程進(jìn)行工作的時(shí)候,它們不需要糾結(jié)于同步的問(wèn)題,于是性能便大大提升。但資源的擴(kuò)張帶來(lái)的是更多的空間消耗,ThreadLocal就是這樣一種利用空間來(lái)?yè)Q取時(shí)間的解決方案。
說(shuō)了這么多,來(lái)看看如何正確使用ThreadLocal。
通過(guò)研究JDK文檔,我們知道,ThreadLocal中有幾個(gè)重要的方法:get()、set()、remove()、initailValue(),對(duì)應(yīng)的含義分別是:
返回此線(xiàn)程局部變量的當(dāng)前線(xiàn)程副本中的值、將此線(xiàn)程局部變量的當(dāng)前線(xiàn)程副本中的值設(shè)置為指定值、移除此線(xiàn)程局部變量當(dāng)前線(xiàn)程的值、返回此線(xiàn)程局部變量的當(dāng)前線(xiàn)程的“初始值”。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
還記得我們?cè)诘谌纳习牍?jié)引出的那個(gè)例子么?幾個(gè)線(xiàn)程修改同一個(gè)Student對(duì)象中的age屬性。為了保證這幾個(gè)線(xiàn)程能夠工作正常,我們需要對(duì)Student的對(duì)象進(jìn)行同步。
下面我們對(duì)這個(gè)程序進(jìn)行一點(diǎn)小小的改造,我們通過(guò)繼承Thread來(lái)實(shí)現(xiàn)多線(xiàn)程:
/**
*
*
@author
x-spirit
*/
public
class
ThreadDemo3
extends
Thread{
private
ThreadLocal
<
Student
>
stuLocal
=
new
ThreadLocal
<
Student
>
();
public
ThreadDemo3(Student stu){
stuLocal.set(stu);
}
public
static
void
main(String[] args) {
Student stu
=
new
Student();
ThreadDemo3 td31
=
new
ThreadDemo3(stu);
ThreadDemo3 td32
=
new
ThreadDemo3(stu);
ThreadDemo3 td33
=
new
ThreadDemo3(stu);
td31.start();
td32.start();
td33.start();
}
@Override
public
void
run() {
accessStudent();
}
public
void
accessStudent() {
String currentThreadName
=
Thread.currentThread().getName();
System.out.println(currentThreadName
+
"
is running!
"
);
Random random
=
new
Random();
int
age
=
random.nextInt(
100
);
System.out.println(
"
thread
"
+
currentThreadName
+
"
set age to:
"
+
age);
Student student
=
stuLocal.get();
student.setAge(age);
System.out.println(
"
thread
"
+
currentThreadName
+
"
first read age is:
"
+
student.getAge());
try
{
Thread.sleep(
5000
);
}
catch
(InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(
"
thread
"
+
currentThreadName
+
"
second read age is:
"
+
student.getAge());
}
}
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
貌似這個(gè)程序沒(méi)什么問(wèn)題。但是運(yùn)行結(jié)果卻顯示:這個(gè)程序中的3個(gè)線(xiàn)程會(huì)拋出3個(gè)空指針異常。讀者一定感到很困惑。我明明在構(gòu)造器當(dāng)中把Student對(duì)象set進(jìn)了ThreadLocal里面阿,為什么run起來(lái)之后居然在調(diào)用stuLocal.get()方法的時(shí)候得到的是NULL呢?
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
帶著這個(gè)疑問(wèn),讓我們深入到JDK的代碼當(dāng)中,去一看究竟。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
原來(lái),在ThreadLocal中,有一個(gè)內(nèi)部類(lèi)叫做ThreadLocalMap。這個(gè)ThreadLocalMap并非java.util.Map的一個(gè)實(shí)現(xiàn),而是利用java.lang.ref.WeakReference實(shí)現(xiàn)的一個(gè)鍵-值對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)其中,key是ThreadLocal類(lèi)型,而value是Object類(lèi)型,我們可以簡(jiǎn)單的視為HashMap<ThreadLocal,Object>。
而在每一個(gè)Thread對(duì)象中,都有一個(gè)ThreadLocalMap的引用,即Thread.threadLocals。而ThreadLocal的set方法就是首先嘗試從當(dāng)前線(xiàn)程中取得ThreadLocalMap(以下簡(jiǎn)稱(chēng)Map)對(duì)象。如果取到的不為null,則以ThreadLocal對(duì)象自身為key,來(lái)取Map中的value。如果取不到Map對(duì)象,則首先為當(dāng)前線(xiàn)程創(chuàng)建一個(gè)ThreadLocalMap,然后以ThreadLocal對(duì)象自身為key,將傳入的value放入該Map中。
ThreadLocalMap getMap(Thread t) {
return
t.threadLocals;
}
public
void
set(T value) {
Thread t
=
Thread.currentThread();
ThreadLocalMap map
=
getMap(t);
if
(map
!=
null
)
map.set(
this
, value);
else
createMap(t, value);
}
而get方法則是首先得到當(dāng)前線(xiàn)程的ThreadLocalMap對(duì)象,然后,根據(jù)ThreadLocal對(duì)象自身,取出相應(yīng)的value。當(dāng)然,如果在當(dāng)前線(xiàn)程中取不到ThreadLocalMap對(duì)象,則嘗試為當(dāng)前線(xiàn)程創(chuàng)建ThreadLocalMap對(duì)象,并以ThreadLocal對(duì)象自身為key,把initialValue()方法產(chǎn)生的對(duì)象作為value放入新創(chuàng)建的ThreadLocalMap中。
public
T get() {
Thread t
=
Thread.currentThread();
ThreadLocalMap map
=
getMap(t);
if
(map
!=
null
) {
ThreadLocalMap.Entry e
=
map.getEntry(
this
);
if
(e
!=
null
)
return
(T)e.value;
}
return
setInitialValue();
}
private
T setInitialValue() {
T value
=
initialValue();
Thread t
=
Thread.currentThread();
ThreadLocalMap map
=
getMap(t);
if
(map
!=
null
)
map.set(
this
, value);
else
createMap(t, value);
return
value;
}
protected
T initialValue() {
return
null
;
}
這樣,我們就明白上面的問(wèn)題出在哪里:我們?cè)趍ain方法執(zhí)行期間,試圖在調(diào)用ThreadDemo3的構(gòu)造器時(shí)向ThreadLocal置入Student對(duì)象,而此時(shí),以ThreadLocal對(duì)象為key,Student對(duì)象為value的Map是被放入當(dāng)前的活動(dòng)線(xiàn)程內(nèi)的。也就是Main線(xiàn)程。而當(dāng)我們的3個(gè)ThreadDemo3線(xiàn)程運(yùn)行起來(lái)以后,調(diào)用get()方法,都是試圖從當(dāng)前的活動(dòng)線(xiàn)程中取得ThreadLocalMap對(duì)象,但當(dāng)前的活動(dòng)線(xiàn)程顯然已經(jīng)不是Main線(xiàn)程了,于是,程序最終執(zhí)行了ThreadLocal原生的initialValue()方法,返回了null。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
講到這里,我想不少朋友一定已經(jīng)看出來(lái)了:ThreadLocal的initialValue()方法是需要被覆蓋的。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
于是,ThreadLocal的正確使用方法是:將ThreadLocal以?xún)?nèi)部類(lèi)的形式進(jìn)行繼承,并覆蓋原來(lái)的initialValue()方法,在這里產(chǎn)生可供線(xiàn)程擁有的本地變量值。
這樣,我們就有了下面的正確例程:
/**
*
*
@author
x-spirit
*/
public
class
ThreadDemo3
extends
Thread{
private
ThreadLocal
<
Student
>
stuLocal
=
new
ThreadLocal
<
Student
>
(){
@Override
protected
Student initialValue() {
return
new
Student();
}
};
public
ThreadDemo3(){
}
public
static
void
main(String[] args) {
ThreadDemo3 td31
=
new
ThreadDemo3();
ThreadDemo3 td32
=
new
ThreadDemo3();
ThreadDemo3 td33
=
new
ThreadDemo3();
td31.start();
td32.start();
td33.start();
}
@Override
public
void
run() {
accessStudent();
}
public
void
accessStudent() {
String currentThreadName
=
Thread.currentThread().getName();
System.out.println(currentThreadName
+
"
is running!
"
);
Random random
=
new
Random();
int
age
=
random.nextInt(
100
);
System.out.println(
"
thread
"
+
currentThreadName
+
"
set age to:
"
+
age);
Student student
=
stuLocal.get();
student.setAge(age);
System.out.println(
"
thread
"
+
currentThreadName
+
"
first read age is:
"
+
student.getAge());
try
{
Thread.sleep(
5000
);
}
catch
(InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(
"
thread
"
+
currentThreadName
+
"
second read age is:
"
+
student.getAge());
}
}
********** 補(bǔ)疑 ******************
有的童鞋可能會(huì)問(wèn):“你這個(gè)Demo根本沒(méi)體現(xiàn)出來(lái),每個(gè)線(xiàn)程里都有一個(gè)ThreadLocal對(duì)象;應(yīng)該是一個(gè)ThreadLocal對(duì)象對(duì)應(yīng)多個(gè)線(xiàn)程,你這變成了一對(duì)一,完全沒(méi)體現(xiàn)出ThreadLocal的作用。”
那么我們來(lái)看一下如何用一個(gè)ThreadLocal對(duì)象來(lái)對(duì)應(yīng)多個(gè)線(xiàn)程:
/** */
/**
*
*
@author
x-spirit
*/
public
class
ThreadDemo3
implements
Runnable
{
private
ThreadLocal
<
Student
>
stuLocal
=
new
ThreadLocal
<
Student
>
()
{
@Override
protected
Student initialValue()
{
return
new
Student();
}
}
;
public
ThreadDemo3()
{
}
public
static
void
main(String[] args)
{
ThreadDemo3 td3
=
new
ThreadDemo3();
Thread t1
=
new
Thread(td3);
Thread t2
=
new
Thread(td3);
Thread t3
=
new
Thread(td3);
t1.start();
t2.start();
t3.start();
}
@Override
public
void
run()
{
accessStudent();
}
public
void
accessStudent()
{
String currentThreadName
=
Thread.currentThread().getName();
System.out.println(currentThreadName
+
"
is running!
"
);
Random random
=
new
Random();
int
age
=
random.nextInt(
100
);
System.out.println(
"
thread
"
+
currentThreadName
+
"
set age to:
"
+
age);
Student student
=
stuLocal.get();
student.setAge(age);
System.out.println(
"
thread
"
+
currentThreadName
+
"
first read age is:
"
+
student.getAge());
try
{
Thread.sleep(
5000
);
}
catch
(InterruptedException ex)
{
ex.printStackTrace();
}
System.out.println(
"
thread
"
+
currentThreadName
+
"
second read age is:
"
+
student.getAge());
}
}
這里,多個(gè)線(xiàn)程對(duì)象都使用同一個(gè)實(shí)現(xiàn)了Runnable接口的ThreadDemo3對(duì)象來(lái)構(gòu)造。這樣,多個(gè)線(xiàn)程使用的ThreadLocal對(duì)象就是同一個(gè)。結(jié)果仍然是正確的。但是仔細(xì)回想一下,這兩種實(shí)現(xiàn)方案有什么不同呢?
答案其實(shí)很簡(jiǎn)單,并沒(méi)有本質(zhì)上的不同。對(duì)于第一種實(shí)現(xiàn),不同的線(xiàn)程對(duì)象當(dāng)中ThreadLocalMap里面的KEY使用的是不同的ThreadLocal對(duì)象。而對(duì)于第二種實(shí)現(xiàn),不同的線(xiàn)程對(duì)象當(dāng)中ThreadLocalMap里面的KEY是同一個(gè)ThreadLocal對(duì)象。但是從本質(zhì)上講,不同的線(xiàn)程對(duì)象都是利用其自身的ThreadLocalMap對(duì)象來(lái)對(duì)各自的Student對(duì)象進(jìn)行封裝,用ThreadLocal對(duì)象作為該ThreadLocalMap的KEY。所以說(shuō),“ThreadLocal的思想精髓就是為每個(gè)線(xiàn)程創(chuàng)建獨(dú)立的資源副本。”這句話(huà)并不應(yīng)當(dāng)被理解成:一定要使用同一個(gè)ThreadLocal對(duì)象來(lái)對(duì)多個(gè)線(xiàn)程進(jìn)行處理。因?yàn)檎嬲脕?lái)封裝變量的不是ThreadLocal。就算是你的程序中所有線(xiàn)程都共用同一個(gè)ThreadLocal對(duì)象,而你真正封裝到ThreadLocalMap中去的仍然是.hashCode()方法返回不同值的不同對(duì)象。就好比線(xiàn)程就是房東,ThreadLocalMap就是房東的房子。房東通過(guò)ThreadLocal這個(gè)中介去和房子里的房客打交道,而房東不管要讓房客住進(jìn)去還是搬出來(lái),都首先要經(jīng)過(guò)ThreadLocal這個(gè)中介。
所以提到ThreadLocal,我們不應(yīng)當(dāng)顧名思義的認(rèn)為JDK里面提供ThreadLocal就是提供了一個(gè)用來(lái)封裝本地線(xiàn)程存儲(chǔ)的容器,它本身并沒(méi)有Map那樣的容器功能。真正發(fā)揮作用的是ThreadLocalMap。也就是說(shuō),事實(shí)上,采用ThreadLocal來(lái)提高并發(fā)行,首先要理解,這不是一種簡(jiǎn)單的對(duì)象封裝,而是一套機(jī)制,而這套機(jī)制中的三個(gè)關(guān)鍵因素(Thread、ThreadLocal、ThreadLocalMap)之間的關(guān)系是值得我們引起注意的。
**************** 補(bǔ)疑完畢 ***************************
可見(jiàn),要正確使用ThreadLocal,必須注意以下幾點(diǎn):
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
1. 總是對(duì)ThreadLocal中的initialValue()方法進(jìn)行覆蓋。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
2. 當(dāng)使用set()或get()方法時(shí)牢記這兩個(gè)方法是對(duì)當(dāng)前活動(dòng)線(xiàn)程中的ThreadLocalMap進(jìn)行操作,一定要認(rèn)清哪個(gè)是當(dāng)前活動(dòng)線(xiàn)程!
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
3. 適當(dāng)?shù)氖褂梅盒停梢詼p少不必要的類(lèi)型轉(zhuǎn)換以及可能由此產(chǎn)生的問(wèn)題。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
運(yùn)行該程序,我們發(fā)現(xiàn):程序的執(zhí)行過(guò)程只需要5秒,而如果采用同步的方法,程序的執(zhí)行結(jié)果相同,但執(zhí)行時(shí)間需要15秒。以前是多個(gè)線(xiàn)程為了爭(zhēng)取一個(gè)資源,不得不在同步規(guī)則的制約下互相謙讓?zhuān)速M(fèi)了一些時(shí)間。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
現(xiàn)在,采用ThreadLocal機(jī)制以后,可用的資源多了,你有我有全都有,所以,每個(gè)線(xiàn)程都可以毫無(wú)顧忌的工作,自然就提高了并發(fā)性,線(xiàn)程安全也得以保證。
當(dāng)今很多流行的開(kāi)源框架也采用ThreadLocal機(jī)制來(lái)解決線(xiàn)程的并發(fā)問(wèn)題。比如大名鼎鼎的 Struts 2.x 和 Spring 等。
把ThreadLocal這樣的話(huà)題放在我們的同步機(jī)制探討中似乎顯得不是很合適。但是ThreadLocal的確為我們解決多線(xiàn)程的并發(fā)問(wèn)題帶來(lái)了全新的思路。它為每個(gè)線(xiàn)程創(chuàng)建一個(gè)獨(dú)立的資源副本,從而將多個(gè)線(xiàn)程中的數(shù)據(jù)隔離開(kāi)來(lái),避免了同步所產(chǎn)生的性能問(wèn)題,是一種“以空間換時(shí)間”的解決方案。
但這并不是說(shuō)ThreadLocal就是包治百病的萬(wàn)能藥了。如果實(shí)際的情況不允許我們?yōu)槊總€(gè)線(xiàn)程分配一個(gè)本地資源副本的話(huà),同步還是非常有意義的。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.tkk7.com/zhangwei217245/
好了,本系列到此馬上就要?jiǎng)澤弦粋€(gè)圓滿(mǎn)的句號(hào)了。不知大家有什么意見(jiàn)和疑問(wèn)沒(méi)有。希望看到你們的留言。
下一講中我們就來(lái)對(duì)之前的內(nèi)容進(jìn)行一個(gè)總結(jié),順便討論一下被遺忘的volatile關(guān)鍵字。敬請(qǐng)期待。
發(fā)表于 2010-04-24 13:36
X-Spirit
閱讀(8411)
評(píng)論(15)
編輯
收藏
所屬分類(lèi):
Java SE
評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)
"總是對(duì)ThreadLocal中的initialValue()方法進(jìn)行覆蓋" ThreadLocal貌似不是這么用的,你現(xiàn)在為每個(gè)線(xiàn)程都 new 一個(gè)對(duì)象當(dāng)然不會(huì)沖突,干脆在 ThreadDemo3 的構(gòu)造方法中 new 好了,使用 ThreadLocal 干嘛?
pwl2014
評(píng)論于 2010-04-08 09:53
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)
@pwl2014
這只是一個(gè)DEMO,使用new在這里其實(shí)就是一個(gè)打比方的方法。如果我用StudentFactory也許更容易接受一點(diǎn),呵呵。
在實(shí)際的應(yīng)用中,我們經(jīng)常可以看到一些用ThreadLocal來(lái)封裝資源的例子。他們無(wú)一例外的都是做一件事情:創(chuàng)建新的資源,供線(xiàn)程使用。例如用ThreadLocal來(lái)處理JDBC 的Connection。即使你沒(méi)有覆蓋initialValue()方法,而是用先get再判空,再set的方式,也還是為一個(gè)沒(méi)有獲取到connection的線(xiàn)程創(chuàng)建一個(gè)connection。
所以,問(wèn)題的關(guān)鍵不在于ThreadLocal使用的時(shí)候采用何種形式。ThreadLocal的思想精髓就是為每個(gè)線(xiàn)程創(chuàng)建獨(dú)立的資源副本。而使用ThreadLocal的時(shí)候最最重要的就是分清楚當(dāng)前活動(dòng)線(xiàn)程是哪個(gè)。
至于覆蓋initialValue()方法的問(wèn)題,這個(gè)應(yīng)該是仁者見(jiàn)仁,智者見(jiàn)智的問(wèn)題,我只是提出一個(gè)能夠節(jié)約代碼量的方案。一般情況下,覆蓋initialValue()方法已經(jīng)可以解決問(wèn)題,這是一種最為經(jīng)濟(jì)的編碼習(xí)慣,它不僅能夠達(dá)到要求,并且和JDK的原生API結(jié)合的很好,不容易出錯(cuò),當(dāng)然如果你需要在用ThreadLocal處理資源之前做一些其他的處理,那就另當(dāng)別論了。
X-Spirit
評(píng)論于 2010-04-08 11:07
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)
嗯,不錯(cuò)!這一系列文章好。。。
anniezheng
評(píng)論于 2010-04-08 19:14
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)
@anniezheng
謝謝夸獎(jiǎng)啦
X-Spirit
評(píng)論于 2010-04-09 00:09
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)
@X-Spirit
這句話(huà)說(shuō)的好,ThreadLocal的思想精髓就是為每個(gè)線(xiàn)程創(chuàng)建獨(dú)立的資源副本。你這個(gè)Demo根本沒(méi)體現(xiàn)出來(lái),每個(gè)線(xiàn)程里都有一個(gè)ThreadLocal對(duì)象;應(yīng)該是一個(gè)ThreadLocal對(duì)象對(duì)應(yīng)多個(gè)線(xiàn)程,你這變成了一對(duì)一,完全沒(méi)體現(xiàn)出ThreadLocal的作用。
路過(guò)
評(píng)論于 2010-04-23 13:42
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
學(xué)習(xí)了!
boiledwater
評(píng)論于 2010-05-18 18:18
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
最近在網(wǎng)上看些關(guān)于線(xiàn)程的東西,開(kāi)始在一個(gè)論壇上找到轉(zhuǎn)載你的一片帖子,然后一路殺過(guò)來(lái),找到了你的大本營(yíng),一口氣看了你寫(xiě)這個(gè)6篇文章,感覺(jué)收獲挺大的,我之前學(xué)習(xí)了struts2,也發(fā)現(xiàn)了它用這個(gè)東西,一直沒(méi)有深究,在這里看到,覺(jué)得一下子發(fā)現(xiàn)了另一座山似的。但是我的疑問(wèn)是ThreadLocal這個(gè)東西的使用場(chǎng)景,還是不太明確。
康博
評(píng)論于 2010-05-28 14:11
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
@康博
感謝你的關(guān)注。關(guān)于應(yīng)用場(chǎng)景的問(wèn)題,我想沒(méi)有什么非常好的例子可以給你。不過(guò)只能告訴你使用ThreadLocal的好處就是可以避免同步帶來(lái)的性能損耗,并且,當(dāng)多個(gè)線(xiàn)程同時(shí)使用同一個(gè)類(lèi)的實(shí)例的時(shí)候,如果這個(gè)實(shí)例不是單例模式的一個(gè)實(shí)現(xiàn),那么ThreadLocal就是值得考慮的。
X-Spirit
評(píng)論于 2010-06-07 00:54
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
@X-Spirit
謝謝你的回復(fù),期待你的下一篇文章。
康博
評(píng)論于 2010-06-12 15:23
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
@康博
呵呵,這個(gè)系列基本上要結(jié)束了。但是由于我最近比較忙,所以本系列的總結(jié)還沒(méi)有時(shí)間整理。不過(guò)過(guò)些日子會(huì)整理出來(lái)的。請(qǐng)保持關(guān)注。
X-Spirit
評(píng)論于 2010-06-12 19:55
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
支持技術(shù)貼,軟件也不錯(cuò)
圣光永恒
評(píng)論于 2010-07-07 18:23
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
技術(shù)的確的支持,頂一下
朱少
評(píng)論于 2010-07-08 16:37
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
好全啊
謝謝樓主
nauxiaoyao
評(píng)論于 2010-07-13 19:19
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
好詳細(xì)
了解了鎮(zhèn)面貌了
nauxiaoyao
評(píng)論于 2010-07-13 19:39
回復(fù)
更多評(píng)論
#
re: Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
不錯(cuò)的編程 支持技術(shù)帖
朱少
評(píng)論于 2010-07-17 12:44
回復(fù)
更多評(píng)論
新用戶(hù)注冊(cè)
刷新評(píng)論列表
只有注冊(cè)用戶(hù)
登錄
后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航:
博客園
IT新聞
Chat2DB
C++博客
博問(wèn)
管理
相關(guān)文章:
【Tech Details】【轉(zhuǎn)】有關(guān)Java SPI機(jī)制
【Effective】Logging最佳實(shí)踐
Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】
Java 多線(xiàn)程同步問(wèn)題的探究(四、協(xié)作,互斥下的協(xié)作——Java多線(xiàn)程協(xié)作(wait、notify、notifyAll))
Java 多線(xiàn)程同步問(wèn)題的探究(三、Lock來(lái)了,大家都讓開(kāi)【2. Fair or Unfair? It is a question...】)
Java 多線(xiàn)程同步問(wèn)題的探究(三、Lock來(lái)了,大家都讓開(kāi)【1. 認(rèn)識(shí)重入鎖】)
Java 多線(xiàn)程同步問(wèn)題的探究(二、給我一把鎖,我能創(chuàng)造一個(gè)規(guī)矩)
Java多線(xiàn)程同步問(wèn)題的探究(一、線(xiàn)程的先來(lái)后到)
【Effective】JVM 調(diào)優(yōu)參數(shù)說(shuō)明
<
2010年4月
>
日
一
二
三
四
五
六
28
29
30
31
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
1
2
3
4
5
6
7
8
常用鏈接
我的隨筆
我的文章
我的評(píng)論
我的參與
最新評(píng)論
留言簿
(6)
給我留言
查看公開(kāi)留言
查看私人留言
隨筆分類(lèi)
(28)
Big Data
(rss)
Cloud
(rss)
Java EE
(rss)
Java FX
(rss)
Java SE(9)
(rss)
Java 輕量級(jí)企業(yè)開(kāi)發(fā)(5)
(rss)
Linux(3)
(rss)
MySQL
(rss)
NetBeans(1)
(rss)
Node.js
(rss)
NoSQL
(rss)
Oracle(3)
(rss)
前端技術(shù)
(rss)
開(kāi)源協(xié)議(1)
(rss)
思維模式
(rss)
悟(1)
(rss)
技術(shù)之外(5)
(rss)
敏捷開(kāi)發(fā)
(rss)
時(shí)間管理
(rss)
隨筆檔案
(90)
2014年9月 (1)
2014年3月 (1)
2014年2月 (1)
2014年1月 (1)
2013年2月 (1)
2012年11月 (1)
2012年10月 (1)
2012年3月 (1)
2012年2月 (1)
2011年2月 (1)
2010年4月 (6)
2010年3月 (4)
2010年1月 (2)
2009年11月 (1)
2009年8月 (1)
2009年7月 (1)
2009年6月 (2)
2009年5月 (1)
2009年4月 (13)
2009年3月 (1)
2009年2月 (1)
2009年1月 (2)
2008年12月 (3)
2008年11月 (1)
2008年10月 (1)
2008年9月 (3)
2008年5月 (1)
2008年4月 (9)
2008年3月 (3)
2008年1月 (1)
2007年12月 (4)
2007年10月 (2)
2007年9月 (6)
2007年8月 (9)
2007年7月 (1)
2007年4月 (1)
文章分類(lèi)
(1)
My Voice(1)
(rss)
文章檔案
(1)
2009年12月 (1)
收藏夾
(4)
別人的學(xué)習(xí)筆記(4)
(rss)
牛人牛博
DaoRu的Blog
(rss)
愛(ài)折騰的道儒
Doug Lea's Home Page
Doug Lea's Home Page
jolestar
老王的博客
Tim Yang
(rss)
后端技術(shù)
Yang_net
(rss)
靠譜IT帥哥
搖擺巴赫@blog.sina
源碼控
搖擺巴赫@javaeye
源碼控
文初的一畝三分地
淘寶放翁
淘寶核心團(tuán)隊(duì)
淘寶核心團(tuán)隊(duì)
福林雨
(rss)
福林的博客
那誰(shuí)的BLOG
那誰(shuí)的BLOG
酷站
ImportNew
學(xué)習(xí)新知、發(fā)現(xiàn)新朋友
InfoQ中文站
InfoQ中文站
InfoQ英文站
InfoQ英文站
Java Code Geeks
A website for Java Geeks
并發(fā)編程網(wǎng)
并發(fā)編程網(wǎng)
開(kāi)源中國(guó)
OSCHINA
百度技術(shù)沙龍
百度技術(shù)沙龍
酷殼
(rss)
酷殼
最新隨筆
1.?【Math's History】什么是羅素悖論
2.?【Effective】IntelliJ IDEA MAC IDE config files
3.?5 Ways To Burn Out Programming
4.?【Efficiency】快速配置ubuntu桌面環(huán)境之Java環(huán)境配置[全軟件源安裝]
5.?【Efficiency】MAC下使用設(shè)定可以從mission control中啟動(dòng)的eclipse.app。
6.?【Effective】如何遷移git倉(cāng)庫(kù)
7.?【轉(zhuǎn)】閱讀我們的學(xué)科——計(jì)算機(jī)專(zhuān)業(yè)學(xué)習(xí)淺談
8.?【Tech Details】【轉(zhuǎn)】有關(guān)Java SPI機(jī)制
9.?【Efficiency】 監(jiān)控 Linux 性能的 18 個(gè)命令行工具
10.?【Effective】Logging最佳實(shí)踐
搜索
最新評(píng)論
1.?re: Java 多線(xiàn)程同步問(wèn)題的探究(三、Lock來(lái)了,大家都讓開(kāi)【1. 認(rèn)識(shí)重入鎖】)
上班
--地點(diǎn)
2.?re: 【轉(zhuǎn)】閱讀我們的學(xué)科——計(jì)算機(jī)專(zhuān)業(yè)學(xué)習(xí)淺談
好文!
--何楊
3.?re: [導(dǎo)入][轉(zhuǎn)]重復(fù)提交、重復(fù)刷新、防止后退的問(wèn)題以及處理方式
是多少
--乒乓、
4.?......
....
--..
5.?re: Java多線(xiàn)程同步問(wèn)題的探究(一、線(xiàn)程的先來(lái)后到)
多線(xiàn)程這塊一直是軟肋,學(xué)習(xí)一下,呵呵
--FlyingFish
閱讀排行榜
1.?Java 多線(xiàn)程同步問(wèn)題的探究(三、Lock來(lái)了,大家都讓開(kāi)【1. 認(rèn)識(shí)重入鎖】)(9054)
2.?Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】(8411)
3.?Java 多線(xiàn)程同步問(wèn)題的探究(二、給我一把鎖,我能創(chuàng)造一個(gè)規(guī)矩)(7440)
4.?Java 多線(xiàn)程同步問(wèn)題的探究(四、協(xié)作,互斥下的協(xié)作——Java多線(xiàn)程協(xié)作(wait、notify、notifyAll))(7252)
5.?Java多線(xiàn)程同步問(wèn)題的探究(一、線(xiàn)程的先來(lái)后到)(7103)
評(píng)論排行榜
1.?Java 多線(xiàn)程同步問(wèn)題的探究(五、你有我有全都有—— ThreadLocal如何解決并發(fā)安全性?)【更新重要補(bǔ)疑】(15)
2.?Java 多線(xiàn)程同步問(wèn)題的探究(三、Lock來(lái)了,大家都讓開(kāi)【1. 認(rèn)識(shí)重入鎖】)(10)
3.?Java 多線(xiàn)程同步問(wèn)題的探究(二、給我一把鎖,我能創(chuàng)造一個(gè)規(guī)矩)(9)
4.?Java 多線(xiàn)程同步問(wèn)題的探究(四、協(xié)作,互斥下的協(xié)作——Java多線(xiàn)程協(xié)作(wait、notify、notifyAll))(9)
5.?Java多線(xiàn)程同步問(wèn)題的探究(一、線(xiàn)程的先來(lái)后到)(8)
Powered by:
博客園
模板提供:
滬江博客
Copyright ©2025 X-Spirit
主站蜘蛛池模板:
免费a级毛片视频
|
亚洲精品午夜国产VA久久成人
|
亚洲一区精品无码
|
亚洲经典在线观看
|
精品特级一级毛片免费观看
|
四虎影视成人永久免费观看视频
|
性色av免费观看
|
亚洲熟妇丰满多毛XXXX
|
国产精品高清视亚洲一区二区
|
国产高清不卡免费在线
|
国产精品无码素人福利免费
|
午夜亚洲国产理论秋霞
|
亚洲AV无码一区二区三区性色
|
免费毛片在线看不用播放器
|
成人免费在线视频
|
黑人精品videos亚洲人
|
亚洲中文字幕无码亚洲成A人片
|
免费观看激色视频网站bd
|
亚洲国产一区视频
|
亚洲一区二区三区无码国产
|
国产区在线免费观看
|
成年女人免费视频播放77777
|
亚洲国产精品无码久久一区二区
|
亚洲日韩乱码中文字幕
|
无码av免费网站
|
亚洲国产成人精品91久久久
|
亚洲AV无码乱码在线观看代蜜桃
|
中文字幕无线码中文字幕免费
|
午夜寂寞在线一级观看免费
|
99人中文字幕亚洲区
|
中国人免费观看高清在线观看二区
|
在线jyzzjyzz免费视频
|
亚洲精品中文字幕乱码影院
|
中文字幕乱码系列免费
|
免费看男女下面日出水视频
|
亚洲卡一卡2卡三卡4麻豆
|
久久精品无码精品免费专区
|
国产成人高清亚洲
|
另类小说亚洲色图
|
四虎在线免费播放
|
亚洲免费黄色网址
|