Varias llamadas a CountDownLatch.await (int) con tiempo de espera
Utilizo un CountDownLatch para esperar un determinado acontecimiento de otro componente (funcionamiento en un hilo diferente). El siguiente enfoque se ajustaría a la semántica de mi software, pero no estoy seguro de si funciona como espero:
mCountDownLatch.await(3000, TimeUnit.MILLISECONDS) otherComponent.aStaticVolatileVariable = true; mCountDownLatch.await(3500, TimeUnit.MILLISECONDS); ... <proceed with other stuff>
El escenario debe ser el siguiente: Espero 3 segundos, y si el latch no se cuenta hasta 0, notifico al otro componente con esa variable, y luego espero como máximo 3.5 segundos. Si hay tiempo de espera de nuevo, entonces no me importa y procederá con otras operaciones.
- Android JobScheduler se ejecuta demasiado a menudo cuando se utiliza setPeriodic ()
- Up-Sync y Down-Sync en Android?
- Añadir cuenta automáticamente
- Android Syncadapter no permitir que el usuario elija sincronizar o no sincronizar
- Cómo sincronizar Android Database con un servidor SQL en línea?
Nota: Sé que no se ve así, pero el escenario anterior es totalmente razonable y válido en mi software.
Leí la documentación de wait (int, TimeUnit) y CountDownLatch, pero no soy un experto en Java / Android, así que necesito confirmación. Para mí, todos los escenarios parecen válidos:
- Si la primera espera es exitosa, entonces la otra espera regresará inmediatamente
- Si los primeros esperan tiempos fuera, entonces el otro espera aún es válido; Por lo tanto, si el otro hilo nota la señal estática, la segunda espera podría volver con éxito
- Ambos esperan llamadas de tiempo de espera (esto está bien de acuerdo a la semántica de mi software)
¿Estoy usando esperar (…) correctamente? ¿Se puede esperar un segundo (…) en la forma anterior, incluso si una espera anterior (…) sobre el mismo objeto se ha agotado?
- ¿Posee un adaptador de sincronización para Android?
- Adaptador de sincronización de contactos en android
- ¿Cómo configurar correctamente el syncAdapter?
- Prácticas recomendadas para sincronizar una base de datos SQL con un servidor remoto REST en Android
- En Android, ¿debe ejecutarse un adaptador de sincronización de contactos en un proceso independiente?
- Patrón de diseño recomendado para escribir en la base de datos SQLite en Android
- SQLiteOpenHelper sincronización
- Cómo administrar el número de subprocesos dentro de la tarea de sincronización
Si entiendo su pregunta correctamente, esta prueba demuestra que todos sus supuestos / requisitos son verdaderos / cumplidos. (Ejecutar con JUnit y Hamcrest.) Tenga en cuenta su código en el método runCodeUnderTest()
, aunque está intercalado con la grabación de tiempo y los tiempos de espera se reducen en un factor de 10.
import org.junit.Before; import org.junit.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.lessThan; import static org.junit.Assert.assertThat; public class CountdownLatchTest { static volatile boolean signal; CountDownLatch latch = new CountDownLatch(1); long elapsedTime; long[] wakeupTimes = new long[2]; @Before public void setUp() throws Exception { signal = false; } @Test public void successfulCountDownDuringFirstAwait() throws Exception { countDownAfter(150); runCodeUnderTest(); assertThat((double) elapsedTime, closeTo(150, 10)); assertThat(wakeupTimeSeparation(), lessThan(10)); } @Test public void successfulCountDownDuringSecondAwait() throws Exception { countDownAfter(450); runCodeUnderTest(); assertThat((double) elapsedTime, closeTo(450, 10)); assertThat((double) wakeupTimeSeparation(), closeTo(150, 10)); } @Test public void neverCountDown() throws Exception { runCodeUnderTest(); assertThat((double) elapsedTime, closeTo(650, 10)); assertThat((double) wakeupTimeSeparation(), closeTo(350, 10)); } @Test public void countDownAfterSecondTimeout() throws Exception { countDownAfter(1000); runCodeUnderTest(); assertThat((double) elapsedTime, closeTo(650, 10)); assertThat((double) wakeupTimeSeparation(), closeTo(350, 10)); } @Test public void successfulCountDownFromSignalField() throws Exception { countDownAfterSignal(); runCodeUnderTest(); assertThat((double) elapsedTime, closeTo(300, 10)); } private int wakeupTimeSeparation() { return (int) (wakeupTimes[1] - wakeupTimes[0]); } private void runCodeUnderTest() throws InterruptedException { long start = System.currentTimeMillis(); latch.await(300, TimeUnit.MILLISECONDS); wakeupTimes[0] = System.currentTimeMillis(); signal = true; latch.await(350, TimeUnit.MILLISECONDS); wakeupTimes[1] = System.currentTimeMillis(); elapsedTime = wakeupTimes[1] - start; } private void countDownAfter(final long millis) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { sleep(millis); latch.countDown(); } }).start(); } private void countDownAfterSignal() { new Thread(new Runnable() { @Override public void run() { boolean trying = true; while (trying) { if (signal) { latch.countDown(); trying = false; } sleep(5); } } }).start(); } private void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { throw new IllegalStateException("Unexpected interrupt", e); } } }