Cómo iniciar dos subprocesos "exactamente" al mismo tiempo

91

Los hilos deben comenzar en la misma fracción de segundo. Entiendo, si lo hace thread1.start(), pasarán algunos milisegundos antes de la próxima ejecución de thread2.start().

¿Es posible o imposible?

Figaro
fuente
2
Una fracción de segundo es un tiempo muy largo a velocidades de GHz.
Nikolai Fetissov
30
No hay necesidad de votar tan intensamente. No todo el mundo entiende el no determinismo relacionado con los hilos, y todos tenemos que empezar por algún lado.
Michael Petrotta
7
No entiendo los votos negativos. La sincronización entre hilos es una necesidad muy común. Sí, en Java, no puede hacer que se ejecuten exactamente en paralelo (lo cual, en otra plataforma puede ser un requisito muy válido por cierto), pero de vez en cuando es muy común que necesite sincronizar su acción. Es por eso que el jdk tiene clases para hacer eso. Tal vez la redacción no fuera precisa, pero diablos, si lo hubiera sabido, no habría hecho la pregunta ..
Enno Shioji
bueno, supongo que entiendo todo tu enfado. Fue una pregunta que me hicieron en una entrevista ... probablemente fue un truco P. Pero, simplemente me confundí y quise confirmarlo. por eso le pregunté si era posible.
figaro
2
@javaguy - no es una pregunta con "trampa". Más bien una pregunta elegida para ver qué tan bien comprende realmente la programación de subprocesos múltiples en general ... también en el caso de Java.
Stephen C

Respuestas:

135

Para iniciar los subprocesos exactamente al mismo tiempo (al menos lo mejor posible), puede usar CyclicBarrier :

// We want to start just 2 threads at the same time, but let's control that 
// timing from the main thread. That's why we have 3 "parties" instead of 2.
final CyclicBarrier gate = new CyclicBarrier(3);

Thread t1 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};
Thread t2 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};

t1.start();
t2.start();

// At this point, t1 and t2 are blocking on the gate. 
// Since we gave "3" as the argument, gate is not opened yet.
// Now if we block on the gate from the main thread, it will open
// and all threads will start to do stuff!

gate.await();
System.out.println("all threads started");

Esto no tiene que ser un CyclicBarrier, también puede usar CountDownLatchun candado o incluso un candado.

Esto todavía no puede garantizar que se inicien exactamente al mismo tiempo en las JVM estándar, pero puede acercarse bastante. Acercarse bastante sigue siendo útil cuando haces, por ejemplo, pruebas de rendimiento. Por ejemplo, si está tratando de medir el rendimiento de una estructura de datos con un número diferente de subprocesos, desea utilizar este tipo de construcción para obtener el resultado más preciso posible.

En otras plataformas, iniciar subprocesos exactamente puede ser un requisito muy válido por cierto.

Enno Shioji
fuente
5
+1 pensamiento agradable ;-) Aunque, por supuesto, no hace que los subprocesos comiencen exactamente al mismo tiempo en tiempo real (al menos no en un chip de un solo núcleo, y no está garantizado incluso en un chip de múltiples núcleos), pero No puedo pensar en ninguna forma de hacerlo mejor.
David Z
¿Se conectará esto a controles de espera específicos del entorno?
ChaosPandion
@ChaosPandion: ¿Te importaría explicarlo?
Santa
@Santa: la API de Win32, por ejemplo, ofrece diferentes primitivas. Un tipo útil es el evento de reinicio manual que se devuelve cuando llama CreateEvent. msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx
ChaosPandion
1
@Zwei - Bueno, sea lo que sea, esta es la respuesta que habría publicado si hubiera sido un gurú de Java.
ChaosPandion
15

No es posible, al menos en una computadora de un solo núcleo. Pero, ¿por qué quieres eso? Incluso si pudo iniciar dos subprocesos exactamente en el mismo segundo, progresarán de manera diferente porque la programación no está bajo su control.

Editar: (En respuesta a algunos de los comentarios) Es un requisito perfectamente válido sincronizar el estado o progreso de múltiples hilos y CyclicBarrieres una gran herramienta. Respondí a la pregunta de si es posible iniciar varios subprocesos exactamente al mismo tiempo . CyclicBarriergarantizará que los subprocesos continúen cuando estén exactamente en el estado deseado, pero no garantiza que se iniciarán o reanudarán exactamente al mismo tiempo, aunque podría estar bastante cerca. No se mencionan las necesidades de sincronización en la pregunta.

samitgaur
fuente
1
Sin embargo, puedes acercarte bastante. Todo depende de las técnicas de sincronización que uses y, por supuesto, de tener más de 1 CPU o núcleo.
ChaosPandion
La idea es que este es un enfoque equivocado y no debería ser necesario en ningún entorno en tiempo real que no sea difícil, no es que sea "bastante cercano".
Nikolai Fetissov
1
Es también imposible porque la programación de subprocesos de Java no le da una precisión de milisegundos.
Stephen C
1
@Zwei - probablemente puedas acercarte "malditamente" la mayor parte del tiempo en una máquina inactiva. Pero si lo necesita todo el tiempo, debe programar en un lenguaje como C, en una máquina con soporte duro en tiempo real en el sistema operativo. Considere también que la JVM podría estar ejecutando un GC completo en la "fracción de segundo" en la que desea iniciar sus subprocesos.
Stephen C
1
Es un problema de sincronización perfectamente válido. Los subprocesos necesitan inicializar algunos datos, asegúrese de que nadie entre en una región crítica sin la validación adecuada. Y el hecho de que CyclicBerrier esté incluido en el paquete concurrente de javas significa que este es un problema importante.
Denis Tulskiy
14

Podrías usar un CountDownLatch para esto. A continuación encontrará una muestra. Aunque t1 y t2 se inician, estos subprocesos siguen esperando hasta que el subproceso principal cuenta hacia atrás el pestillo. El número de cuentas atrás necesarias se menciona en el constructor. El pestillo de cuenta regresiva también se puede usar para esperar a que los subprocesos terminen de ejecutarse para que el subproceso principal pueda continuar más (el caso inverso). Esta clase se incluyó desde Java 1.5.

import java.util.concurrent.CountDownLatch;


public class ThreadExample
{
    public static void main(String[] args) 
    {
        CountDownLatch latch = new CountDownLatch(1);
        MyThread t1 = new MyThread(latch);
        MyThread t2 = new MyThread(latch);
        new Thread(t1).start();
        new Thread(t2).start();
        //Do whatever you want
        latch.countDown();          //This will inform all the threads to start
        //Continue to do whatever
    }
}

class MyThread implements Runnable
{
    CountDownLatch latch;
    public MyThread(CountDownLatch latch) 
    {
        this.latch = latch;
    }
    @Override
    public void run() 
    {
        try 
        {
            latch.await();          //The thread keeps waiting till it is informed
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Do the actual thing
    }
}
aNish
fuente
Esta respuesta podría beneficiarse de menos repetición en el ejemplo de código.
user2418306
6
  1. Según tengo entendido, la JVM delega principalmente estas cosas al sistema operativo. Entonces, la respuesta será específica del sistema operativo.
  2. Es claramente imposible en máquinas de un solo procesador.
  3. Es más complicado con respecto a una máquina multiprocesador. Según la relatividad de la simultaneidad , "es imposible decir en un sentido absoluto si dos eventos ocurren al mismo tiempo si esos eventos están separados en el espacio". No importa qué tan cerca estén sus procesadores, están separados en el espacio.
    1. Si puede aceptar la simultaneidad relativa, entonces probablemente sea más fácil simularla usando técnicas discutidas en otras respuestas.
emory
fuente
1
... e incluso si asumimos un inicio simultáneo, cada hilo tiene su propia línea de tiempo, todos ellos son concurrentes , pero no necesariamente paralelos, por lo que cualquier cosa que alguien asuma sobre la simultaneidad de hilos puede (será) nula en el próximo nanosegundo (de lo que sea línea de tiempo)…
Holger