2011-09-04 13 views
7

Mam problem, który nie wydaje mi się, że ma rozwiązanie, ale i tak spróbuję tutaj. Moja aplikacja używa puli wątków, a niektóre wątki w tej puli mają dziedziczną zmienną lokalną wątku. Rozszerzyłem klasę ThreadPoolExecutor, aby zasadniczo usunąć zmienną lokalną wątku (w metodzie afterExecute) po zakończeniu wykonywania wątku.InheritableThreadLocal i puli wątków

Rozumiem, że gdy masz zmienną InheritableThreadLocal, metoda childValue() jest wywoływana, gdy wątek jest inicjowany, aby uzyskać wartość zmiennej ThreadLocal z wątku rodzica. Jednak w moim przypadku przy następnym użyciu wątku (po jego użyciu raz) wartość zmiennej InheritableThreadLocal ma wartość NULL (ponieważ została wcześniej wyczyszczona w AfterExecute). Czy istnieje sposób dostępu do zmiennej lokalnej wątku wątku macierzystego przedExecute, aby w zasadzie móc symulować, co robi metoda childValue w InheritableThreadLocal w momencie tworzenia wątku.

+1

Czemu wyczyszczenie wątek wartość lokalnego wątku podrzędnego jeśli trzeba go później? Czy wartości wymagane w następnym uruchomieniu z innego wątku nadrzędnego, czy też zostały zmienione w obiekcie nadrzędnym, ponieważ wątek potomny został najpierw utworzony? –

+0

@ Bert - to jest właśnie powód. Zasadniczo przechowuję identyfikator żądania w zmiennej lokalnej wątku, która zmienia się w wielu zastosowaniach wątku podrzędnego. – neesh

Odpowiedz

4

Wygląda na to, że jest to kiepski przypadek użycia dla "dziedzicznego" smaku nitkowatych.

Moja rada to użycie zwykłego TheadLocal i jawne inicjowanie; na przykład przekazywanie wartości początkowej z wątku nadrzędnego do wątku podrzędnego jako parametru lub czegoś podobnego.

(Chciałam zasugerować, abyś zainicjował wątek-lokalny wątek potomny, pobierając jego wartość zaraz po uruchomieniu, ale to zagraża warunkowi wyścigu, np. Jeśli wątek nadrzędny jest zwracany do basen przed wątku dziecko zaczyna wykonaniem.)


Chyba co pytam jest, jeśli istnieje sposób, aby uzyskać dostęp do wartości zmiennej lokalnej wątku wątku dominującej z wątku dziecięcej.

Nie ma sposobu, aby to zrobić.

I, sądząc po twoich innych komentarzach, wątpię, że masz na myśli "rodzic" i "dziecko" w normalnym znaczeniu ... gdzie nić rodzicielska tworzy wątek potomny.

Ale tu jest pomysł. Zamiast próbować udostępniać zmienną między wątkami, udostępniać stałą wartość (np. Identyfikator żądania) i używać go jako klucza do udostępnionego Map. Użyj wpisów Map jako zmiennych udostępnianych.

+1

dzięki za odpowiedź. Jestem ciekawy, jak mógłbym zainicjować wątek-lokalny wątku potomnego. Chyba pytam, czy istnieje sposób dostępu do wartości zmiennej lokalnej wątku wątku macierzystego z wątku podrzędnego. – neesh

+0

Niestety ta odpowiedź pozostawia problem otwarty. W jaki sposób wątek lokalny może być przenoszony z jednego wątku na drugi.Jeśli jest to dziecko drugiego, to InheritableThreadLocals wykonuje to zadanie ładnie, ale co robisz w przypadku puli wątków? – Gregor

+0

Dlaczego udzieliłeś odpowiedzi? To trochę nieuprzejme, aby ująć odpowiedź, która stwierdza, że ​​nie istnieje dobre rozwiązanie ... tylko dlatego, że nie podoba ci się ten fakt. Z pewnością nie zachęca mnie to do pomocy! –

0

Konstruktor działającego w wątku wywołującego, natomiast metoda run działa w wątku podrzędnym. Możesz użyć tego faktu do przeniesienia informacji z rodzica na wątek podrzędny. Zobacz:

public class ThreadlocalApplication { 
static public ThreadLocal<String> tenantId = new ThreadLocal<>(); 

public static void main(String[] args) throws ExecutionException, InterruptedException { 
    ExecutorService executor = Executors.newCachedThreadPool(); 
    System.out.println(Thread.currentThread().getName()); 
    ThreadlocalApplication.tenantId.set("4711"); 
    executor.submit(new AsyncTask()).get(); 
    executor.shutdown(); 
} 

static class AsyncTask implements Runnable { 
    private String _tenantId; 

    public AsyncTask() { 
     System.out.println(Thread.currentThread().getName()); 
     _tenantId = ThreadlocalApplication.tenantId.get(); 
    } 

    @Override 
    public void run() { 
     ThreadlocalApplication.tenantId.set(_tenantId); 
     System.out.println(Thread.currentThread().getName()); 
     System.out.println(ThreadlocalApplication.tenantId.get()); 
    } 
} 
} 

I to jest wynik

main 
main 
pool-1-thread-1 
4711 
Powiązane problemy