Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Я действительно рекомендовал бы пройти учебное руководство как Параллелизм 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
пакет и подпакеты. Действительно необходимо найти, что материал онлайн узнает параллелизм или получает хорошую книгу.
Используйте CountDownLatch со счетчиком 1.
CountDownLatch latch = new CountDownLatch(1);
Теперь в потоке приложения делают -
latch.await();
В потоке дб, после того, как Вы сделаны, сделайте -
latch.countDown();
будущее интерфейс от java.lang.concurrent
пакет разработан для обеспечения доступа к результатам, вычисленным в другом потоке.
Смотрят на FutureTask и ExecutorService для готового способа сделать такого рода вещь.
я настоятельно рекомендовал бы читать Параллелизм Java На практике любому заинтересованному параллелизмом и многопоточностью. Это, очевидно, концентрируется на Java, но существует много сути для кого-либо работающего на других языках также.
Вы могли сделать это с помощью Обменник объект, совместно использованный двумя потоками:
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) {
}
, Поскольку другие сказали, не берите это беззаботное и просто код вставки копии. Сделайте некоторое чтение сначала.
Если Вы хотите что-то быстрое и грязное, можно просто добавить Thread.sleep () вызов в цикле с условием продолжения. Если библиотека базы данных - что-то, что Вы не можете изменить, то нет действительно никакого другого легкого решения. Опрос базы данных до готов с периодом ожидания, не уничтожит производительность.
while (!dbthread.isReady()) {
Thread.sleep(250);
}
Едва что-то, что Вы могли назвать изящный код, но сделали работу.
В случае, если можно изменить код базы данных, затем с помощью взаимного исключения, как предложено в других ответах, лучше.
Это относится ко всем языкам:
Вы хотите иметь модель события/слушателя. Вы создаете слушателя для ожидания конкретного события. Событие было бы создано (или сообщено) в Вашем рабочем потоке. Это заблокирует поток, пока сигнал не будет получен вместо того, чтобы постоянно опросить, чтобы видеть, соблюдают ли условие, как решение Вы в настоящее время имеете.
Ваша ситуация является одной из наиболее распространенных причин для мертвых блокировок - удостоверяются, что Вы предупреждаете о другом потоке независимо от ошибок, которые, возможно, произошли. Пример - если Ваше приложение выдает исключение - и никогда не называет метод для передачи сигналов о другом, что вещи завершились. Это сделает его так, другой поток никогда не 'просыпается'.
я предлагаю, чтобы Вы изучили понятие использования событий и обработчиков событий для лучше понимания этой парадигмы прежде, чем реализовать случай.
, Кроме того, можно использовать блокирующийся вызов функции с помощью взаимного исключения - который заставит поток ожидать ресурса, чтобы быть свободным. Чтобы сделать это, Вам нужна хорошая синхронизация потока - такая как:
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
Попробуйте класс CountDownLatch из java.util.concurrent
пакет, который обеспечивает высокоуровневые механизмы синхронизации, которые намного менее подвержены ошибкам, чем любой низкоуровневый материал.
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 (),