Как запустить два потока в одно и то же время

Потоки должны начинаться в ту же долю секунды. Я понимаю, если вы делаете thread1.start(), это займет несколько миллисекунд до следующего выполнения thread2.start(),

Это вообще возможно или невозможно?

5 ответов

Решение

Чтобы запустить потоки в одно и то же время (хотя бы настолько хорошо, насколько это возможно), вы можете использовать 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");

Это не должно быть CyclicBarrierВы также можете использовать CountDownLatch или даже замок.

Это по-прежнему не может гарантировать, что они запускаются точно в одно и то же время на стандартных JVM, но вы можете подойти довольно близко. Приближение довольно близко все еще полезно, когда вы делаете, например, тесты производительности. Например, если вы пытаетесь измерить пропускную способность структуры данных с различным числом потоков, попадающих на нее, вы хотите использовать этот вид конструкции, чтобы получить максимально точный возможный результат.

На других платформах запуск потоков точно может быть очень допустимым требованием.

Вы можете использовать CountDownLatch для этого. Пожалуйста, найдите ниже образец. Хотя t1 и t2 запущены, эти потоки продолжают ждать, пока основной поток не начнет отсчет защелки. Количество необходимых отсчетов указано в конструкторе. Защелка обратного отсчета может также использоваться для ожидания завершения потоков, чтобы основной поток мог продолжить работу (обратный случай). Этот класс был включен с 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
    }
}

Это невозможно, по крайней мере, на одноядерном компьютере. Но почему ты этого хочешь? Даже если вы смогли запустить два потока в одну и ту же секунду, они будут развиваться по-разному, потому что планирование не находится под вашим контролем.

Редактировать: (в ответ на некоторые комментарии) Это совершенно обоснованное требование для синхронизации состояния или прогресса нескольких потоков и CyclicBarrier это отличный инструмент. Я ответил на вопрос, возможно ли запускать несколько потоков одновременно. CyclicBarrier будет гарантировать, что потоки продолжатся, когда они будут точно в желаемом состоянии, но это не гарантирует, что они начнутся или возобновятся в одно и то же время, хотя это может быть довольно близко. Там нет упоминания о необходимости синхронизации в этом вопросе.

  1. Насколько я понимаю, JVM в основном делегирует эти вещи операционной системе. Таким образом, ответ будет зависеть от ОС.
  2. Это явно невозможно на однопроцессорных машинах.
  3. Это сложнее в отношении многопроцессорной машины. Согласно Относительности одновременности, "невозможно в абсолютном смысле сказать, происходят ли два события одновременно, если эти события разделены в пространстве". Независимо от того, насколько близко ваши процессоры, они разделены в пространстве.
    1. Если вы можете принять относительную одновременность, то, вероятно, проще просто смоделировать ее, используя методы, описанные в других ответах.

Я проверил предлагаемые ответы и заметил, что использование классических спин-блокировок работает лучше при запуске потоков в «один и тот же момент», а вероятность успеха при столкновении потоков выше.

      AtomicInteger startedThreadsCount = new AtomicInteger(0);
AtomicBoolean spinLock = new AtomicBoolean(true);


void collide(Runnable runnable) {

    for (int i = 0; i < threadsCount; i++) {
      executor.execute(() -> decorate(runnable));
    }

    while (startedThreadsCount.get() < threadsCount)
      ;

    spinLock.set(false);
}

void decorate(Runnable runnable) {

    startedThreadsCount.incrementAndGet();

    while (startedThreadsCount.get() < threadsCount)
      ;

    while (spinLock.get())
      ;

     runnable.run();
  }

Я создал библиотеку коллайдеров потоков , которая пытается запускать потоки «точно» в одно и то же время, чтобы выявить проблемы параллелизма, например, при простом модульном тестировании.

Другие вопросы по тегам