Как заставить поток Java ожидать вывода другого потока?

Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException вообще.

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

125
задан Piskvor cc-by-sa 3.0 9 May 2016 в 19:17
поделиться

8 ответов

Я действительно рекомендовал бы пройти учебное руководство как Параллелизм Java Sun перед открытием в волшебном мире многопоточности.

существует также много хороших книг (Google для "Параллельного Программирования в Java", "Параллелизм Java на практике".

Для получения до ответа:

В Вашем коде, который должен ожидать эти dbThread, у Вас должно быть что-то вроде этого:

//do some work
synchronized(objectYouNeedToLockOn){
    while (!dbThread.isReady()){
        objectYouNeedToLockOn.wait();
    }
}
//continue with work after dbThread is ready

В Вашем dbThread метод, необходимо было бы сделать что-то вроде этого:

//do db work
synchronized(objectYouNeedToLockOn){
    //set ready flag to true (so isReady returns true)
    ready = true;
    objectYouNeedToLockOn.notifyAll();
}
//end thread run method here

objectYouNeedToLockOn я использую в этих примерах, предпочтительно объект, которым необходимо управлять одновременно от каждого потока, или Вы могли создать отдельное Object с этой целью (я не рекомендую делать сами методы синхронизируемыми):

private final Object lock = new Object();
//now use lock in your synchronized blocks

К далее Вашему пониманию:
существуют другие (иногда лучше) способы сделать вышеупомянутое, например, с CountdownLatches, и т.д. Начиная с Java 5, там много изящных классов параллелизма в java.util.concurrent пакет и подпакеты. Действительно необходимо найти, что материал онлайн узнает параллелизм или получает хорошую книгу.

127
ответ дан 24 November 2019 в 00:57
поделиться

Используйте CountDownLatch со счетчиком 1.

CountDownLatch latch = new CountDownLatch(1);

Теперь в потоке приложения делают -

latch.await();

В потоке дб, после того, как Вы сделаны, сделайте -

latch.countDown();
135
ответ дан 24 November 2019 в 00:57
поделиться

будущее интерфейс от java.lang.concurrent пакет разработан для обеспечения доступа к результатам, вычисленным в другом потоке.

Смотрят на FutureTask и ExecutorService для готового способа сделать такого рода вещь.

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

4
ответ дан 24 November 2019 в 00:57
поделиться

Вы могли сделать это с помощью Обменник объект, совместно использованный двумя потоками:

private Exchanger<String> myDataExchanger = new Exchanger<String>();

// Wait for thread's output
String data;
try {
  data = myDataExchanger.exchange("");
} catch (InterruptedException e1) {
  // Handle Exceptions
}

И во втором потоке:

try {
    myDataExchanger.exchange(data)
} catch (InterruptedException e) {

}

, Поскольку другие сказали, не берите это беззаботное и просто код вставки копии. Сделайте некоторое чтение сначала.

6
ответ дан 24 November 2019 в 00:57
поделиться

Если Вы хотите что-то быстрое и грязное, можно просто добавить Thread.sleep () вызов в цикле с условием продолжения. Если библиотека базы данных - что-то, что Вы не можете изменить, то нет действительно никакого другого легкого решения. Опрос базы данных до готов с периодом ожидания, не уничтожит производительность.

while (!dbthread.isReady()) {
  Thread.sleep(250);
}

Едва что-то, что Вы могли назвать изящный код, но сделали работу.

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

2
ответ дан 24 November 2019 в 00:57
поделиться

Это относится ко всем языкам:

Вы хотите иметь модель события/слушателя. Вы создаете слушателя для ожидания конкретного события. Событие было бы создано (или сообщено) в Вашем рабочем потоке. Это заблокирует поток, пока сигнал не будет получен вместо того, чтобы постоянно опросить, чтобы видеть, соблюдают ли условие, как решение Вы в настоящее время имеете.

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

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

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

Thread-A Locks lock-a
Run thread-B
Thread-B waits for lock-a
Thread-A unlocks lock-a (causing Thread-B to continue)
Thread-A waits for lock-b 
Thread-B completes and unlocks lock-b
2
ответ дан 24 November 2019 в 00:57
поделиться

Попробуйте класс CountDownLatch из java.util.concurrent пакет, который обеспечивает высокоуровневые механизмы синхронизации, которые намного менее подвержены ошибкам, чем любой низкоуровневый материал.

7
ответ дан 24 November 2019 в 00:57
поделиться
public class ThreadEvent {

    private final Object lock = new Object();

    public void signal() {
        synchronized (lock) {
            lock.notify();
        }
    }

    public void await() throws InterruptedException {
        synchronized (lock) {
            lock.wait();
        }
    }
}

Используйте этот класс следующим образом:

Создайте ThreadEvent:

ThreadEvent resultsReady = new ThreadEvent();

В методе ожидаются результаты:

resultsReady.await();

И в методе, который создает результаты после того, как были созданы все результаты:

resultsReady.signal();

РЕДАКТИРОВАТЬ:

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

Вы можете использовать это, только если вы на 100% уверены, что signal () вызывается после await (). Это одна из основных причин, по которой вы не можете использовать объект Java, например, Windows Events.

Если код выполняется в следующем порядке:

Thread 1: resultsReady.signal();
Thread 2: resultsReady.await();

, то поток 2 будет ждать вечно . Это потому, что Object.notify () пробуждает только один из запущенных в данный момент потоков. Поток, ожидающий позже, не пробуждается. Это сильно отличается от того, как я ожидаю, что события будут работать, когда событие сигнализируется до тех пор, пока а) не будет выполнено ожидание или б) явно не сброшено.

Примечание. В большинстве случаев следует использовать notifyAll (),

8
ответ дан 24 November 2019 в 00:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: