2011-09-04 20 views
7

Ho un problema che in realtà non penso abbia una soluzione, ma ci proverò comunque. La mia applicazione utilizza un pool di thread e alcuni thread in questo pool dispongono di una variabile locale thread ereditabile. Ho esteso la classe ThreadPoolExecutor per eliminare essenzialmente la variabile locale del thread (nel metodo call back afterExecute) quando viene eseguito un thread.InheritableThreadLocal e pool di thread

Capisco che quando si dispone di una variabile InheritableThreadLocal, viene chiamato il metodo childValue() quando il thread viene inizializzato per ottenere il valore della variabile ThreadLocal dal thread padre. Tuttavia, nel mio caso la prossima volta che si utilizza il thread (dopo essere stato utilizzato una sola volta), il valore della variabile InheritableThreadLocal è null (poiché è stato precedentemente eliminato in afterExecute). Esiste un modo per accedere alla variabile locale del thread del thread principale in beforeExecute in modo da poter essenzialmente simulare cosa fa il metodo childValue in InheritableThreadLocal al momento della creazione del thread.

+1

Perché si sta cancellando filo valore locale del thread figlio se ne avete bisogno in seguito? I valori necessari alla prossima esecuzione provengono da un thread padre diverso o sono stati modificati nel genitore da quando il thread secondario è stato creato per la prima volta? –

+0

@Bert - questo è esattamente il motivo. Fondamentalmente sto memorizzando un ID di richiesta nella variabile locale del thread che cambia attraverso molteplici usi del thread secondario. – neesh

risposta

4

Sembra che questo sia un caso di utilizzo inadeguato per il sapore "ereditabile" dei locali.

Il mio consiglio sarebbe quello di utilizzare solo un normale TheadLocal e fare l'inizializzazione in modo esplicito; per esempio. passare il valore iniziale dal thread padre al thread figlio come parametro o qualcosa.

(stavo andando a suggerire di forzare l'inizializzazione del thread-local il thread secondario facendolo recuperare il valore non appena viene avviato, ma ciò rischia una condizione di competizione, ad esempio se il thread padre viene restituito al piscina prima che il thread figlio inizia l'esecuzione.)


Credo che quello che sto chiedendo è se c'è un modo per accedere al valore della variabile locale filo del thread genitore da un thread figlio.

Non c'è un modo per farlo.

E, a giudicare dai tuoi altri commenti, dubito che tu intenda "genitore" e "figlio" nel senso normale ... dove il thread padre crea il thread secondario.

Ma ecco un'idea. Invece di provare a condividere una variabile tra thread, condividere un valore fisso (ad esempio un ID di richiesta) e utilizzarlo come chiave per uno Map condiviso. Utilizzare le voci Map come variabili condivise.

+1

grazie per la risposta. Sono curioso di sapere come forzare l'inizializzazione del thread-local del thread figlio. Immagino che cosa sto chiedendo è se c'è un modo per accedere al valore della variabile locale del thread del thread padre da un thread figlio. – neesh

+0

Sfortunatamente questa risposta lascia aperto il problema. Come può un thread locale essere trasferito da un thread all'altro.Se l'uno è figlio dell'altro, allora InheritableThreadLocals fa bene il lavoro, ma cosa fai in caso di un pool di thread? – Gregor

+0

Perché hai ridiscusso la risposta? È un po 'scortese sottopormare una risposta che afferma che non esiste una buona soluzione ... solo perché non ti piace questo fatto. Certamente, non mi incoraggia ad aiutarti! –

0

Il costruttore di un'esecuzione eseguibile nel thread del chiamante, mentre il metodo run viene eseguito nel thread secondario. È possibile utilizzare questo fatto per trasferire informazioni dal genitore al thread secondario. Vedere:

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()); 
    } 
} 
} 

E questo è il risultato

main 
main 
pool-1-thread-1 
4711 
Problemi correlati