Как приостановить, а затем возобновить поток?
Я утверждаю, что читаю о потоке, но я никогда не использовал.
Поэтому я прошу вас:)
У меня есть два потока: A
и B
,
где A
управляет GUI, а B
управляет логикой.
Я бы начал с A
.
Затем, когда A
нарисует графический интерфейс, я приостановил его, чтобы подождать B
, которые достигают точки X в методе запуска.
И когда B
достигает метода X в методе запуска, я приостанавливаю B
и возобновляю A
.
A
и B
совместно использовать некоторую переменную для управления графическим интерфейсом и логикой...
Могу ли я это сделать? если да, то как?:)
Ответы
Ответ 1
Используя методы wait()
и notify()
:
wait()
- Вызывает текущий поток ждать, пока другой поток не вызывает notify()
метод или notifyAll()
метод для этого объекта.
notify()
- пробуждает единственный поток, который ожидает на этом мониторе объекта.
Ответ 2
Вы можете заблокировать потоки, используя методы wait
и notify
класса Object, но это может быть сложно сделать правильно. Вот пример внутри бесконечного цикла в Runnable:
public class Example implements Runnable {
private volatile boolean running = true;
private volatile boolean paused = false;
private final Object pauseLock = new Object();
@Override
public void run() {
while (running) {
synchronized (pauseLock) {
if (!running) { // may have changed while waiting to
// synchronize on pauseLock
break;
}
if (paused) {
try {
synchronized (pauseLock) {
pauseLock.wait(); // will cause this Thread to block until
// another thread calls pauseLock.notifyAll()
// Note that calling wait() will
// relinquish the synchronized lock that this
// thread holds on pauseLock so another thread
// can acquire the lock to call notifyAll()
// (link with explanation below this code)
}
} catch (InterruptedException ex) {
break;
}
if (!running) { // running might have changed since we paused
break;
}
}
}
// Your code here
}
}
public void stop() {
running = false;
// you might also want to interrupt() the Thread that is
// running this Runnable, too, or perhaps call:
resume();
// to unblock
}
public void pause() {
// you may want to throw an IllegalStateException if !running
paused = true;
}
public void resume() {
synchronized (pauseLock) {
paused = false;
pauseLock.notifyAll(); // Unblocks thread
}
}
};
(Для получения дополнительной информации о том, почему нам нужно синхронизировать, как показано выше, во время вызова wait
и notifyAll
, см. Учебник Java по этому вопросу.)
Если другой Поток вызывает этот метод Runnable pause()
, то Поток, выполняющий runnable, заблокируется, когда достигнет вершины цикла while.
Обратите внимание, что невозможно приостановить поток в любой произвольной точке. Вам нужен поток, чтобы периодически проверять, должна ли она приостановиться и заблокировать себя, если это так.
Ответ 3
Я бы ожидал, что вам не нужно приостанавливать поток GUI. Операционная система позаботится об этом, и она должна быть готова ответить, если пользователь что-то сделает.
Еще одна мысль - убедиться, что общие переменные правильно синхронизированы между двумя потоками. Я попытался ответить на вопрос, связанный с этим в последнее время, см. здесь.
Ответ 4
вы можете использовать CountDownLatch
. Когда Thread A должен ждать, пока Thread B вызовет countDownLatchInstance.await();
Когда B достигнет точки X, вы вызовете countDownLatchInstance.countDown()
; позволяя A продолжить поток выполнения.
Когда вы говорите
A управляет графическим интерфейсом
Надеюсь, вы не ссылаетесь на UI/Main Thread
Ответ 5
То, как я получил поток, подождать и уведомить, работая на меня:
public class Main {
public static void main(String[] args) {
final Object lock = new Object();
MyThread t = new MyThread();
t.lock = lock;
t.run();
while (true) {
try {
synchronized (lock) {
lock.wait();
}
System.out.println("hello");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class MyThread extends Thread {
Object lock;
@Override
public void run() {
JFrame fr = new JFrame("Anothing");
JButton btn = new JButton("Next");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
synchronized (lock) {
lock.notify();
}
}
});
fr.setLayout(new FlowLayout());
fr.add(btn);
fr.setSize(400, 400);
fr.setVisible(true);
}
}
Затем, когда я нажимаю кнопку, другой поток просыпается, выполняет один раунд и ждет нового нажатия.
Ответ 6
Java-примитив для приостановки и возобновления потока устарел. Посмотрите это, чтобы понять, как вы можете добиться наилучшего, что вам нужно - http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
Проверьте, как вы можете сделать эквивалент приостановки и возобновить
Что следует использовать вместо Thread.suspend
и Thread.resume
?
Как и в случае с Thread.stop
, разумный подход заключается в том, чтобы опрос "целевой нити" включал переменную, указывающую желаемое состояние потока (активное или приостановленное). Когда желаемое состояние приостановлено, поток ожидает использования Object.wait
. Когда поток возобновляется, целевой поток уведомляется с помощью Object.notify
.
Пример кода приведен в том же ответе, который поможет вам достичь этого.