2010-05-08 89 views
4

語境:有沒有辦法迭代或複製Java ThreadLocal的所有值?

static ThreadLocal<MyType> threadLocalMyType = ... 

什麼,我想是這樣說:

for (ThreadLocalEntry e: threadLocalMyType.getMapLikeThing() { 
    // Thread t = e.getKey(); 
    // I don't need the thread value right now, but it might be useful for 
    // something else. 

    MyType theMyType = e.getValue(); 
    // [...do something with theMyType...] 
} 
+2

也許更有趣的問題是,你爲什麼要這麼做? – 2010-05-08 20:09:38

+0

好吧,這個想法無論好壞,都有辦法收集多個線程中的更改列表,然後每隔一段時間執行一次所有更改。它看起來像是一種避免同步的自然方式,因爲這些更改僅針對特定的線程進行排序。 – 2010-05-08 20:16:45

+0

查看[我的答案](http://stackoverflow.com/a/15654081/113632)給相關的問題;如果您需要訪問'ThreadLocal'中的所有值,則根本不需要'ThreadLocal'。通常,你需要一個'ConcurrentHashMap '。 – dimo414 2015-08-17 15:48:57

回答

5

一種方式是手工處理這個問題:

  • 使用ThreadLocal包裝(擴展它)
  • 每當的值被設置,保持線程的(staticMap S和值

可替換地,一些反射(getDeclaredMethod()setAccessible(true)),可以:

  • 呼叫Thread.getThreads()
  • 呼叫yourThreadLocal.getMap(thread)(對於每個上述的線程)
  • 呼叫map.getEntry(yourThreadLocal)

的第一是更優選的。

+1

我想,簡而言之,這個問題的答案是'否',對我來說解決方案只是簡單的「靜態ConcurrentHashMap 」......儘管這樣做會放棄ThreadLocal的優化。 – 2010-05-08 20:42:32

+0

感謝您的討論,doublep和Bozho;如果我有代表...我會接受Bozho的答案,因爲它概括了兩種解決方案,但由於我沒有_have_使用ThreadLocal,我將使用ConcurrentHashMap來代替。 – 2010-05-08 21:07:02

+1

@Jonas:如果你使用'ThreadLocal'主要是爲了獲取而不是設置,你可以採用這種方式。據我瞭解,Bozho提出的是:當設置一個值時,也可以在其他地圖中複製它。然後,線程可以從ThreadLocal中有效地獲取,而其他線程可以從同步的(因此效率較低的)輔助存儲中讀取。儘管如果該值指向某個對象,請考慮訪問它是否需要額外的同步。 – doublep 2010-05-08 21:09:27

1

沒有,因爲在內部它是實現不同的:每個線程都有當地人的地圖狀的東西。你想要做什麼是本質上就是線程不安全如果ThreadLocal允許它。每個線程在訪問自己的本地時顯然不使用任何類型的同步:沒有其他線程可以這樣做,因此不需要同步。出於這個原因,從任何其他線程訪問本地地圖(如果可能的話)將是線程不安全的。

由於Bozho建議,你可以做到這一點通過繼承ThreadLocal和其他地方複製值。不要忘記正確地同步訪問「別的地方」。

+0

我意識到這個類是爲了一個單一的目的,線程本地對象;所以我們不能責怪ThreadLocal設計師沒有包含一個機制來做我想在這裏做的事情(我敢肯定它可以線程安全地完成,但可能會導致優化降低,並且與名字'本地',因爲我解釋你上面說的)。我恐怕在問這個問題之前我還沒有完全理解它。 – 2010-05-08 21:03:16

+0

是的,正如我看到'ThreadLocal'可以實現此功能,但它將不得不同步訪問內部映射,從而增加了常見情況下不需要的開銷。 – doublep 2010-05-08 21:07:03

+0

讓我們爲Java-7提出一個ThreadGlocal ... – 2010-05-08 21:22:08

1

我來到acrosss同樣的問題,在這裏看到的答案後,我決定使用一種混合的方法:

public class PersistentThreadLocal<T> extends ThreadLocal<T> { 

    final Map<Thread, T> allValues; 
    final Supplier<? extends T> valueGetter; 

    public PersistentThreadLocal(Supplier<? extends T> initialValue) { 
     this(0, initialValue); 
    } 

    public PersistentThreadLocal(int numThreads, Supplier<? extends T> initialValue) { 
     allValues = Collections.synchronizedMap(
      numThreads > 0 ? new WeakHashMap<>(numThreads) : new WeakHashMap<>() 
     ); 
     valueGetter = initialValue; 
    } 

    @Override 
    protected T initialValue() { 
     T value = valueGetter != null ? valueGetter.get() : super.initialValue(); 
     allValues.put(Thread.currentThread(), value); 
     return value; 
    } 

    @Override 
    public void set(T value) { 
     super.set(value); 
     allValues.put(Thread.currentThread(), value); 
    } 

    @Override 
    public void remove() { 
     super.remove(); 
     allValues.remove(Thread.currentThread()); 
    } 

    public Collection<T> getAll() { 
     return allValues.values(); 
    } 

    public void clear() { 
     allValues.clear(); 
    } 
} 

編輯:如果你打算用ThreadPoolExecutor的使用中,WeakHashMap更改爲常規HashMap,否則會發生奇怪的事情!

+0

看起來它會起作用! – 2017-11-15 16:30:29

相關問題