Более простой способ синхронизации 2 потоков в Java? - PullRequest
6 голосов
/ 12 августа 2011

Я не хочу быть уверенным, что какой-то кусок моего кода в основном потоке будет выполнен после того, как какой-то фрагмент кода будет выполнен с использованием вторичного потока.Вот что я получил:

    final Object lock = new Object();
    final Thread t = new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                System.out.println("qwerty");
                lock.notify();
            }
        }
    });

    synchronized(lock) {
        t.start();
        lock.wait();
    }

    System.out.println("absolutely sure, qwerty is above");
  1. Это правильное решение?
  2. Есть ли более короткие способы сделать то же самое?

Ответы [ 4 ]

12 голосов
/ 12 августа 2011

Такие вещи, как notify () и wait () являются действительно низкоуровневыми примитивами синхронизации.

Вы должны использовать абстракции более высокого уровня, когда это возможно, например, в этом случае, скажем, CountDownLatch .

Ниже приведен лишь пример, который должен помочь вам начать работу (например, здесь не учитываются проблемы с тайм-аутом):

    final CountDownLatch latch = new CountDownLatch(1);
    final Thread t = new Thread(new Runnable() {
        public void run() {
            System.out.println("qwerty");
            latch.countDown();
        }
    });

    t.start();
    latch.await();

    System.out.println("absolutely sure, qwerty as been printed");

Низкоуровневые вещи, такие как wait и notify , на самом деле являются просто низкоуровневыми особенностями Java, о которых вам не следует беспокоиться (если вы не пишете API параллелизма). 1018 *

Кроме того, я бы предложил прочитать удивительную книгу: Параллелизм Java на практике .

5 голосов
/ 12 августа 2011

Предполагая, что вашему основному потоку нужно инициировать обработку вторичного потока, Обменник будет самым простым решением.

Если вторичный поток является независимым, то подходит некоторая форма BlockingQueue .


Пример использования Exchanger (с правильной обработкой исключений). Один обменник может быть заменен двумя очередями.

public static void main(String[] argv)
throws Exception
{
    final Exchanger<String> exchanger = new Exchanger<String>();
    new Thread(new Runnable() 
    {
        @Override
        public void run() 
        {
            try
            {
                String s = exchanger.exchange("");
                System.out.println(s);
                exchanger.exchange("this came from subthread");
            }
            catch (InterruptedException ex)
            {
                System.out.println("interrupted while waiting for message");
            }
        }
    }).start();

    exchanger.exchange("this came from main thread");
    String s = exchanger.exchange("");
    System.out.println(s);
}
0 голосов
/ 12 августа 2011

Лучшее решение для кода, который вы дали:

System.out.println("qwerty");
System.out.println("absolutely sure, qwerty is above");

Не используйте многопоточность, когда она вам не нужна.

Но если вы знаете, что делаете с потоком, то решение @ DoubleMalt - это правильный путь (t.join()).

Вы также, вероятно, нашли бы, что стоит прочитать http://download.oracle.com/javase/tutorial/essential/concurrency/

0 голосов
/ 12 августа 2011
final Thread t = new Thread(new Runnable() {
    public void run() {
        System.out.println("qwerty");
    }
});

t.start();
t.join();

System.out.println("absolutely sure, qwerty is above");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...