variable thread sincronizar sincronizacion programacion metodos hilos fuente ejemplos codigo clase acceso java concurrency synchronization

thread - sincronizar acceso a variable hilos java



Sincronización Java 1.4: ¿solo permite ejecutar una instancia de método(sin bloqueo)? (4)

Esto es realmente idéntico al código que se requiere para administrar la construcción de un Singleton (¡jadeo!) Cuando se hace de la manera clásica:

if (instance == null) { synchronized { if (instance == null) { instance = new SomeClass(); } } }

La prueba interna es idéntica a la prueba externa. La prueba externa es para que no ingresemos de manera rutinaria en un bloque sincronizado, la prueba interna es para confirmar que la situación no ha cambiado desde la última vez que realizamos la prueba (el hilo podría haberse adelantado antes de ingresar Sincronizado).

En tu caso:

if (translationsNeedLoading()) { synchronized { if (translationsNeedLoading()) { loadTranslations(); } } }

ACTUALIZACIÓN: esta forma de construir un singleton no funcionará de manera confiable bajo su JDK1.4. Para una explicación, mira aquí . Sin embargo, creo que eres, estarás bien en este escenario.

Tengo una clase que propone utilidades de traducción. Las traducciones mismas deben volver a cargarse cada 30 minutos. Yo uso el soporte Spring Timer para eso. Básicamente, mi clase se ve así:

public interface Translator { public void loadTranslations(); public String getTranslation(String key); }

loadTranslations () puede ser bastante largo de ejecutar, por lo tanto, mientras se está ejecutando, las traducciones antiguas todavía están disponibles. Esto se hace cargando las traducciones en un Mapa local y simplemente cambiando la referencia cuando se cargan todas las traducciones.

Mi problema es: ¿cómo puedo asegurarme de que cuando un hilo ya esté cargando traducciones, el segundo también intente ejecutarlo, lo detecte y lo devuelva inmediatamente, sin iniciar una segunda actualización?

Un método sincronizado solo pondrá en cola las cargas ... Todavía estoy en Java 1.4, entonces no java.util.concurrent.

Gracias por tu ayuda !


Mantenga un control sobre el hilo de carga para ver si se está ejecutando?

¿O no puedes simplemente usar una bandera sincronizada para indicar si una carga está en progreso?


Soy de un fondo .net (sin experiencia java en absoluto), pero podrías probar una bandera estática simple de algún tipo que verifique al principio del método si se está ejecutando. Entonces, todo lo que necesita hacer es asegurarse de que cualquier lectura / escritura de esa bandera esté sincronizada. Por lo tanto, al principio compruebe la bandera, si no está configurada, configúrela, si está configurada, vuelva. Si no está configurado, ejecute el resto del método y, una vez finalizado, desconéctelo. Solo asegúrate de poner el código en un try / finally y la bandera en la posición final, para que siempre se desactive en caso de error. Muy simplificado, pero puede ser todo lo que necesita.

Editar: Esto probablemente funciona mejor que sincronizar el método. Porque realmente necesitas una nueva traducción inmediatamente después de la antes de que termine? Y es posible que no desee bloquear un hilo durante demasiado tiempo si tiene que esperar un tiempo.


Use alguna forma de mecanismo de bloqueo para realizar solo la tarea si aún no está en progreso. La adquisición del token de bloqueo debe ser un proceso de un solo paso. Ver:

/** * @author McDowell */ public abstract class NonconcurrentTask implements Runnable { private boolean token = true; private synchronized boolean acquire() { boolean ret = token; token = false; return ret; } private synchronized void release() { token = true; } public final void run() { if (acquire()) { try { doTask(); } finally { release(); } } } protected abstract void doTask(); }

Código de prueba que lanzará una excepción si la tarea se ejecuta simultáneamente:

public class Test { public static void main(String[] args) { final NonconcurrentTask shared = new NonconcurrentTask() { private boolean working = false; protected void doTask() { System.out.println("Working: " + Thread.currentThread().getName()); if (working) { throw new IllegalStateException(); } working = true; try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } if (!working) { throw new IllegalStateException(); } working = false; } }; Runnable taskWrapper = new Runnable() { public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } shared.run(); } } }; for (int i = 0; i < 100; i++) { new Thread(taskWrapper).start(); } } }