Лучший способ запустить два потока в качестве альтернативы?

Обновление: см. В нижней части этого вопроса для полного ответа.

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

Я пришел к двум различным решениям, я не знаю, какое из них лучше, и у меня есть вопросы по поводу первого:

Использование обменника

Я пришел к чему-то, используяОбменник (пока я не хочу обменивать только один объект).

@Test
public void launchMyTest() {
    /**
     * An anonymous class to set some variables from a different thread
     */
    class ThreadTest extends Thread {
        //declare some various attributes that will be set
        //NOT DECLARED VOLATILE
        ...

        public final Exchanger<Integer> exchanger = new Exchanger<Integer>();

        @Override
        public void run() {
            try {
                //start of the synchronization 
                int turn = 1;
                while (turn != 2) {
                    turn = this.exchanger.exchange(turn);
                }

                //do some work and set my various variables
                ...

                //main thread's turn
                turn = 1;
                this.exchanger.exchange(turn);
                //wait for this thread's turn
                while (turn != 2) {
                    turn = this.exchanger.exchange(turn);
                }

                //redo some other work and reset the various variables
                ...

                //main thread's turn
                turn = 1;
                this.exchanger.exchange(turn);

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } 
        }
    }


    try {
        //some work in the main thread
        ....

        //launch the job in the second thread
        ThreadTest test = new ThreadTest();
        test.start();
        //start of the synchronization
        int turn = 2;
        test.exchanger.exchange(turn);
        //wait for this thread's turn
        while (turn != 1) {
            turn = test.exchanger.exchange(turn);
        }

        //run some tests using the various variables of the anonymous class
        ....

        //now, relaunch following operations in the second thread
        turn = 2;
        test.exchanger.exchange(turn);
        //wait for this thread's turn
        while (turn != 1) {
            turn = test.exchanger.exchange(turn);
        }

        //do some other tests using the various variables of the anonymous class
        //...

    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}
Вопрос:Я прав, чтоexchange Метод выполняет синхронизацию памяти, так же, как использованиеLock?Используя Условие

Другое решение с использованиемУсловие:

@Test
public void launchMyTest() {
    /**
     * An anonymous class to set some variables from a different thread
     */
    class ThreadTest extends Thread {
        //declare some various attributes that will be set
        //NOT DECLARED VOLATILE
        ...

        public final Lock lock = new ReentrantLock();
        public final Condition oneAtATime = lock.newCondition();
        public int turn = 1;

        @Override
        public void run() {
            this.lock.lock();
            try {
                //do some work and set my various variables
                ...

                //main thread's turn
                this.turn = 1;
                this.oneAtATime.signal();

                //wait for this thread's turn
                while (this.turn != 2) {
                    this.oneAtATime.await();
                }

                //redo some other work and reset the various variables
                ...

                //main thread's turn
                this.turn = 1;
                this.oneAtATime.signal();

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                this.lock.unlock();
            }
        }
    }


    ThreadTest test = new ThreadTest();
    test.lock.lock();
    try {
        //some work in the main thread
        ....

        //launch the job in the second thread
        test.turn = 2;
        test.start();
        //wait for this thread's turn
        while (test.turn != 1) {
            test.oneAtATime.await();
        }

        //run some tests using the various variables of the anonymous class
        ....

        //now, relaunch following operations in the second thread
        test.turn = 2;
        test.oneAtATime.signal();
        //wait for this thread's turn
        while (test.turn != 1) {
            test.oneAtATime.await();
        }

        //do some other tests using the various variables of the anonymous class
        //...

    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } finally {
        test.lock.unlock();
    }
}

Это кажется мне немного сложнее.

Заключение

Как вы думаете, это лучшее решение? Я делаю это правильно, или я пропускаю другое очевидное решение?

Я не использовалCountDownLatch как я хочу бежатьнесколько операции поочередно, иCountDownLatch не может быть сброшено И я не обнаружил, чтоCyclicBarrier делал код проще ... (на самом деле я не совсем понял, как его использовать, но он не выглядел проще, чем использоватьExchanger или жеCondition)

Спасибо.

Обновить

@ Clément MATHIEU предоставил различные примеры того, как этого добиться, в комментарияхпринятый ответ, видеть:https://gist.github.com/cykl/5131021

Есть три примера, один с использованиемCyclicBarrierеще один, использующийExchangerи последний использует 2Semaphores. Хотя он прав, говоря, что «более выразительным является семафор на основе», я решил использоватьExchanger для простоты. Мой юнит тест стал:

@Test
public void launchMyTest() {
    /**
     * An anonymous class to set some variables from a different thread
     */
    class ThreadTest extends Thread {
        //declare some various attributes that will be set
        //NOT DECLARED VOLATILE
        ...
        public final Exchanger<Integer> exchanger = new Exchanger<Integer>();

        @Override
        public void run() {
            try {
                //do some work and set my various variables
                ...

                //main thread's turn
                this.exchanger.exchange(null);
                //wait for this thread's turn
                this.exchanger.exchange(null);

                //redo some other work and reset the various variables
                ...

                //main thread's turn
                this.exchanger.exchange(null);

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } 
        }
    }


    try {
        //some work in the main thread
        ....

        //launch the job in the second thread
        ThreadTest test = new ThreadTest();
        test.start();
        //wait for this thread's turn
        test.exchanger.exchange(null);

        //run some tests using the various variables of the anonymous class
        ....

        //now, relaunch following operations in the second thread
        test.exchanger.exchange(null);
        //wait for this thread's turn
        test.exchanger.exchange(null);

        //do some other tests using the various variables of the anonymous class
        //...

    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

Ответы на вопрос(4)

Ваш ответ на вопрос