2011-09-04 9 views
7

Tengo un problema que realmente no creo que tenga una solución, pero lo intentaré de todos modos. Mi aplicación utiliza un grupo de subprocesos y algunos de los subprocesos de este grupo tienen una variable local de subproceso heredable. Extendí la clase ThreadPoolExecutor para borrar esencialmente la variable local thread (en el método de devolución de llamada afterExecute) cuando se termina de ejecutar un subproceso.InheritableThreadLocal and thread pools

Entiendo que cuando se tiene una variable InheritableThreadLocal, se invoca el método childValue() cuando se inicializa el hilo para obtener el valor de la variable ThreadLocal del hilo padre. Sin embargo, en mi caso, la próxima vez que se utiliza el subproceso (después de ser utilizado una vez), el valor de la variable InheritableThreadLocal es nulo (porque se eliminó previamente en afterExecute). ¿Hay alguna manera de acceder a la variable local de subproceso principal del subproceso en beforeExecute para que pueda simular esencialmente lo que hace el método childValue en InheritableThreadLocal en el momento de la creación del subproceso?

+1

¿Por qué estás limpiando valor local hilo del hilo hijo si lo necesita más adelante? ¿Los valores necesarios en la próxima ejecución provienen de una secuencia padre diferente o han cambiado en la matriz desde la primera vez que se creó? –

+0

@Bert: esa es precisamente la razón. Básicamente, estoy almacenando un id. De solicitud en la variable local de subprocesos que cambia a través de múltiples usos del subproceso secundario. – neesh

Respuesta

4

Suena como que este es un mal caso de uso para el sabor "heredable" de locales de temas.

Mi consejo sería simplemente usar un TheadLocal regular y hacer la inicialización explícitamente; p.ej. pasando el valor inicial del subproceso principal al subproceso secundario como un parámetro o algo.

(Yo estaba sugiriendo que fuerce la inicialización del subproceso local del subproceso al hacer que recupere el valor tan pronto como se inicia. Pero eso corre el riesgo de una condición de carrera, por ejemplo, si el subproceso principal se devuelve al la piscina antes de que el hilo hijo se inicia la ejecución.)


Creo que lo que estoy pidiendo es que si hay una manera de acceder al valor de rosca variable local de la rosca de los padres de un hilo hijo.

No hay una manera de hacer esto.

Y, a juzgar por sus otros comentarios, dudo que quiera decir "padre" y "hijo" en el sentido normal ... donde el hilo padre crea el hilo hijo.

Pero aquí está una idea. En lugar de intentar compartir una variable entre subprocesos, comparta un valor fijo (por ejemplo, un ID de solicitud) y utilícelo como clave para un Map compartido. Use las entradas Map como las variables compartidas.

+1

gracias por la respuesta. Tengo curiosidad de cómo podría forzar a inicializar el subproceso local del subproceso secundario. Supongo que lo que estoy preguntando es si hay una forma de acceder al valor de la variable local de subproceso padre del subproceso desde un subproceso secundario. – neesh

+0

Desafortunadamente, esta respuesta deja el problema abierto. ¿Cómo se puede transferir un hilo local de un hilo a otro?Si el uno es un hijo del otro, entonces InheritableThreadLocals hace el trabajo bien, pero ¿qué haces en caso de un grupo de hilos? – Gregor

+0

¿Por qué rechazaste la respuesta? Es un poco grosero rechazar una respuesta que afirma que no existe una buena solución ... solo porque no te gusta ese hecho. ¡Ciertamente, no me alienta a ayudarte! –

0

El constructor de un ejecutable se ejecuta en el hilo de la persona que llama, mientras que el método de ejecución se ejecuta en el subproceso secundario. Puede usar este hecho para transferir información del padre al hilo hijo. Ver:

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

Y este es el resultado

main 
main 
pool-1-thread-1 
4711