Teo
Teo

Reputation: 3213

How pause and then resume a thread?

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

Answers (7)

daiscog
daiscog

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

CooderSK
CooderSK

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

lfvv
lfvv

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

Dineshkumar
Dineshkumar

Reputation: 4245

Using wait() and notify() methods:

wait() - Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

notify() - Wakes up a single thread that is waiting on this object's monitor.

Upvotes: 32

user93353
user93353

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 and Thread.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 using Object.wait. When the thread is resumed, the target thread is notified using Object.notify.

Example code is given in the same answer to help you achieve this.

Upvotes: 0

Blackbelt
Blackbelt

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

Stochastically
Stochastically

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

Related Questions