Reputation: 3213
I state that I read about thread, but I've never used. So I ask to you :)
I have two thread: A
and B
,
where A
manages the GUI, and B
manages the logic.
I would start with A
.
Then when A
draw the GUI, I would pause it, to wait B
that reach a point X into run method.
And when B
reach the X point into run method, I pause B
, and resume A
.
A
and B
share some variable to manage the GUI, and the logic...
Can I do it? if yes, how? :)
Upvotes: 54
Views: 131422
Reputation: 12077
You can block threads using the wait
and notify
methods of the Object class, but it can be tricky to get right. Here's an example inside an infinite loop in a 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 {
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
}
}
};
(For more information on why we need to synchronize as illustrated above whilst calling wait
and notifyAll
, see the Java tutorial on the subject.)
If another Thread calls this Runnable's pause()
method, then the Thread running the runnable will block when it gets to the top of the while loop.
Note that it is not possible to pause a thread at any arbitrary point. You need the Thread to periodically check whether it should pause and block itself if so.
Upvotes: 28
Reputation: 237
public class Mutex {
private final AtomicBoolean lock;
private final Object mutex;
public Mutex(boolean lock) {
this.lock = new AtomicBoolean(lock);
this.mutex = new Object();
}
public void step() {
if (lock.get()) synchronized(mutex) {
try {
mutex.wait();
} catch (InterruptedException ex) {}
}
}
public void lock() {
lock.set(true);
}
public void unlock() {
lock.set(false);
synchronized(mutex) {
mutex.notify();
}
}
}
Just add Mutex object to your thread and make getter.
public class MyThread extends Thread {
private final Mutex mutex;
public MyThread() {
this.mutex = new Mutex(false);
}
public Mutex getMutex() {
return this.mutex;
}
@Override
public void run() {
while (!isInterrupted()) {
mutex.step();
// do your code
}
}
}
If you want to pause the thread just call
myThread.getMutex().lock();
If you want to resume the thread just call
myThread.getMutex().unlock();
Upvotes: 3
Reputation: 1639
That's the way I got thread's wait and notify working for me:
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);
}
}
Then, whenever I press the button, the other thread wakes up, executes one round and waits for a new clicking.
Upvotes: 2
Reputation: 4245
Using wait()
and notify()
methods:
wait()
- Causes the current thread to wait until another thread invokes thenotify()
method or thenotifyAll()
method for this object.
notify()
- Wakes up a single thread that is waiting on this object's monitor.
Upvotes: 32
Reputation: 14049
The java primitive to suspend and resume a thread is deprecated. See this to figure how you can achieve best what you need - http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html Check how you can do the equivalent of suspend & resume
What should I use instead of
Thread.suspend
andThread.resume
?As with
Thread.stop
, the prudent approach is to have the "target thread" poll a variable indicating the desired state of the thread (active or suspended). When the desired state is suspended, the thread waits usingObject.wait
. When the thread is resumed, the target thread is notified usingObject.notify
.
Example code is given in the same answer to help you achieve this.
Upvotes: 0
Reputation: 157487
you can use a CountDownLatch
. When Thread A has to wait for Thread B will call countDownLatchInstance.await();
When B reach the X point will invoke countDownLatchInstance.countDown()
; allowing A to continue its execution flow.
When you say
A manages the GUI
I hope you do not refer to the UI/Main Thread
,
Upvotes: 4
Reputation: 7846
I would expect that you don't need to pause the GUI thread. The operating system will take care of that, and it needs to be ready to respond in case the user does something.
One other thought is to make sure the shared variables are properly synchronized between the two threads. I tried answering a question relating to that recently, see here.
Upvotes: 4