2010-01-29 63 views
2

您好我有類定義這樣ThreadLocal的行爲

public class JdbcInterceptor { 
private static final JdbcInterceptor instance = new JdbcInterceptor(); 
private static ThreadLocal<Boolean> dontIntercept = new ThreadLocal<Boolean>(); 
    public static JdbcInterceptor getInstance() { 
return instance; 
} 
public void skipIntercept() { 
dontIntercept.set(true); 
} 
public boolean interrupt() { 
boolean di = dontIntercept.get()!=null?dontIntercept.get().booleanValue():false; 
if (di) { 
     dontIntercept.set(false); 
     } 
return di; 
}// end interrupt 
}// end class 

,我這樣做是一些其他的Class1現在

//class1 stuff 
JdbcInterceptor.getInstance().skipIntercept(); 
if(JdbcInterceptor.getInstance().interrupt()) 
{ // class1 stuff happens 
} 

我在Class2中做到這一點

//class2 stuff 
if(JdbcInterceptor.getInstance().interrupt()) 
{ // class2 stuff happens 
} 

現在我有點困惑,我知道class1的東西會發生,因爲我設置了 dontIntercept ThreadLocal。我的疑問是class2的東西是否會發生? 我的邏輯是我只有一個JdbcInterceptor實例,因此在所有調用interrupt()的狀態下都應該有相同的狀態。但是我被告知ThreadLocals對於每個線程都是本地的。我在這裏看到一些衝突。請幫助我。

回答

4

你的問題不是很清楚。

但我被告知ThreadLocals對於每個線程都是本地的。我在這裏看到一些衝突。

這是正確的。沒有衝突。與ThreadLocal一起存儲的值對象對於每個線程都是唯一的。它實際上在內部與Thread對象一起存儲,所以當線程終止時全部線程本地值也被刪除並可用於垃圾收集,除非其他線程有其他引用。

如果您的兩個類都使用相同的線程執行,那麼除非您更改調用之間的線程本地值,否則它們將具有相同的結果。如果一個不同的線程執行class2,那麼它們會有不同的值(按照你的例子)。

您可能會在時間和類/方法存儲和代碼中發生混淆的線程執行。這兩個是非常不同的。一個線程可以執行任何和所有方法,或者可以有多個線程在同一個類中執行相同的方法。你不能在代碼中「看到」線程。如果沒有其他的圖片,你必須想象它們 - 它確實需要一些細緻的可視化。

現在你可以讓你的代碼使用ThreadLocal初始化,這樣更清晰一點:

private static ThreadLocal<Boolean> dontIntercept = new ThreadLocal<Boolean>() { 

    @Override 
    protected Boolean initialValue() { 
     return Boolean.FALSE; 
    } 

}; 

然後,當你使用線程局部你沒有檢查它是否是null,就像這樣:

public boolean interrupt() { 
    return dontIntercept.get().booleanValue(); 
}// end interrupt 

下面就來介紹如何這可能與更多的兩個線程執行的嘗試:

Thread1 start---class1(skip=false)-+-skip(true)---+class1(true)--+class2(true)----+-end 
        |    |    |    |    | 
        Thread2 start---+-class1(false)+--------------+class2(false)---+-class1(false)---end 

當我顯示classN(val)時,該值是當時跳過線程局部變量設置的值。

爲了更具體地回答你的問題,在這個例子中:class1和class2的代碼在被thread1執行時都會被跳過。當由thread2執行時,它們不會被跳過。

請注意,還有另一種本地線程稱爲InheritableThreadLocal。在我的示例中,這會有不同的行爲線程2將會在線程啓動第二個線程時接收線程1中的值。

編輯如果您在class1中的代碼始終將skip值設置爲true,則行爲會發生一些變化。如果線程先執行class1,那麼class2然後跳過將爲true。如果一個線程先執行class2然後執行class1,那麼前者的skip將爲false,後者則爲true。您不會顯示有任何方法可以跳轉回false

編輯重讀您的問題。如果你實際上想要所有線程完全相同的狀態,那麼你不會使用ThreadLocal。只需使用常規變量,並將其標記爲volatile或使用同步來保護它。

+0

衝突我的意思是隻有一個類的實例返回成員變量的不同值之間的衝突。 – 2010-01-29 09:05:33

+0

編輯的代碼顯示我如何設置跳到假。 – 2010-01-29 09:19:19

+0

如果這是你的意圖,這不是衝突。 ThreadLocals用於此目的。對於新代碼,由於在class1中執行的值始終設置爲「true」,方法跳過,然後重置爲「false」,所以事件順序不同。使用新代碼沒有理由 - 只需刪除class1中的代碼並刪除class2中的if if即可。 – 2010-01-29 09:48:13