Синхронизация потоков - Как выполнять потоки альтернативно - PullRequest
4 голосов
/ 14 февраля 2010

Я пытался решить проблему, связанную с обменом потоками, используя wait () и notify (). В основном у меня есть 2 потока T1 и T2, и я хочу, чтобы они выполнялись в следующем порядке

T1, T2, T1, T2 ..... Как мне этого добиться?

Фактическая проблема: есть 2 потока T1 - который печатает нечетные числа (скажем 1 - 100) и T2 - который печатает четные числа (1 - 100) Теперь на выходе должно быть 1, 2, 3, 4, 5, .... 100

Ответы [ 4 ]

3 голосов
/ 14 февраля 2010

Вы описываете модель «производитель-потребитель».

Это реализации Java, описанные в многочисленных книгах Java, в том числе М.Гранд "Образцы в Java. Том I" и "Java 2: Полный справочник" Нотона и Шильдта.

Основная идея: оба потока должны использовать 1 монитор (т.е. их код должен быть внутри synchronized(monitor) {} блоков). Вам также нужна переменная-флаг, которая должна указывать, какой из двух потоков должен работать в данный момент.

Когда один из ваших потоков находится в синхронизированном блоке, он должен проверить переменную флага, не пора ли он выполнять работу. Если да, дайте ему поработать, затем измените значение флага, а затем уведомите все ожидающие потоки. Если нет, то стоит подождать.

2 голосов
/ 14 февраля 2010

Посмотрите на пакет java.util.concurrent, а именно Обменник

1 голос
/ 14 февраля 2010

Вы пытаетесь распараллелить многошаговый процесс, верно? Если это так, см. Мой ответ здесь для подхода и некоторого рабочего кода для этого. Ответ включает в себя ExecutorService (или две) и одну или несколько рабочих очередей.

Для этого подхода ваша обработка должна быть в состоянии соответствовать Runnable вместе с промежуточной информацией о состоянии для обработки. Вы подаете каждый шаг в ExecutorService как Runnable, который добавляет второй Runnable для выполнения следующего шага. Это поддерживает порядок выполнения, но позволяет эффективно запускать столько потоков, сколько вы желаю параллельно.

: EDIT:

Как предложил другой, для этого можно использовать библиотечный класс Exchanger , если вы явно хотите ограничить обработку до 2 потоков. Я предпочитаю описанный выше подход, поскольку он поддерживает порядок выполнения и позволяет полностью использовать современные 4-ядерные (и 8-ядерные) системы. Это также должно немного уменьшить синхронизацию.

0 голосов
/ 04 июня 2014

Если T1 и T2 - это две разные реализации интерфейса Runnable, причем T1 - это поток, который печатает только нечетные числа (1,3, ...), а T2 - тот, который печатает четное число (1,2 ... ..), это можно сделать с помощью методов wait () и notify () на общем мониторе. Важно, чтобы каждый поток проверял наличие общего флага перед печатью его значения. Приведенный ниже код работает;

//The shared monitor
public class Mutex {
public static boolean oddFlag;

}

//The Thread that is supposed to print Odd numbers (assuming an upper limit of 99)
public class OddPrinter implements Runnable {
private Mutex mutex;

public OddPrinter(Mutex mutex) {
    this.mutex = mutex;
}

public synchronized void run() {
    System.out.println("Started Thread: OddPrinter");
    int i;
    for(i=1; i<100; i+=2 ) {
        synchronized (mutex) {
            while(!Mutex.oddFlag) {
                try {
                    mutex.wait();
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupted();
                }
            }

            if(Mutex.oddFlag == true) {
                System.out.println("Print from OddPrinter: "+i);
                Mutex.oddFlag = false;
                mutex.notify();
            }


        }
    }
    System.out.println("Finished Thread: OddPrinter: "+i);
}

}

//The Thread that is supposed to print Odd numbers (assuming an upper limit of 98)
public class EvenPrinter implements Runnable {
private Mutex mutex;

public EvenPrinter(Mutex mutex) {
    this.mutex = mutex;
}

public synchronized void run() {
    System.out.println("Started Thread: EvenPrinter");
    int i;
    for(i=2; i<100; i+=2) {
        synchronized (mutex) {
            while(Mutex.oddFlag) {
                try {
                    mutex.wait();
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupted();
                }
            }

            if(!(Mutex.oddFlag == true)) {
                System.out.println("Print from EvenPrinter: "+i);
                Mutex.oddFlag = true;
                mutex.notify();
            }

        }
    }
    System.out.println("Finished Thread: EvenPrinter: "+i);
}

}

//The test harness that executes the threads
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class NumberPrinterTest {

public static void main(String[] args) throws Exception{
    ExecutorService es = Executors.newFixedThreadPool(2);

    Mutex mutex = new Mutex();
    OddPrinter op = new OddPrinter(mutex);
    EvenPrinter ep = new EvenPrinter(mutex);
    Mutex.oddFlag = true;
    es.execute(op);
    es.execute(ep);

    if(null != es){
        es.shutdown();
        try {
            es.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupted();
        }
    }

}

}
...