如何暂停然后恢复一个线程?

时间:2013-05-26 10:31:48

标签: java multithreading

我声明我读过线程,但我从未使用过。 所以我问你:)

我有两个主题:AB, 其中A管理GUI,B管理逻辑。

我会从A开始。

然后当A绘制GUI时,我会暂停它,等待到达X点的B进入run方法。

B到达X点运行方式时,我会暂停B,然后恢复A

AB共享一些变量来管理GUI和逻辑......

我可以这样做吗?如果有,怎么样? :)

7 个答案:

答案 0 :(得分:20)

使用wait()notify()方法:

  

wait() - 使当前线程等待,直到另一个线程调用   notify()方法或此对象的notifyAll()方法。

     

notify() - 唤醒正在此对象监视器上等待的单个线程。

答案 1 :(得分:13)

您可以使用Object类的waitnotify方法来阻止线程,但要正确起来可能会很棘手。这是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
        }
    }
};

(有关我们在调用waitnotifyAll时如上所述同步的原因的详细信息,请参阅the Java tutorial on the subject。)

如果另一个Thread调用此Runnable的pause()方法,则运行runnable的Thread将在到达while循环的顶部时阻塞。

请注意,无法在任意点暂停线程。你需要Thread来定期检查它是否应该暂停并阻塞它自己。

答案 2 :(得分:4)

我希望您不需要暂停GUI线程。操作系统将负责这一点,并且需要准备好响应以防用户做某事。

另一个想法是确保共享变量在两个线程之间正确同步。我最近尝试回答了与此相关的问题,请参阅here

答案 3 :(得分:3)

您可以使用CountDownLatch。当线程A必须等待线程B将调用countDownLatchInstance.await();当B到达X点时将调用countDownLatchInstance.countDown();允许A继续执行流程。

当你说

  

A管理GUI

我希望你不要参考UI/Main Thread

答案 4 :(得分:1)

这就是我让线程等待并通知为我工作的方式:

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);
    }
}

然后,每当我按下按钮,另一个线程醒来,执行一轮并等待新的点击。

答案 5 :(得分:1)

job-name: 
  script:
    - echo "i am potato"
  rules:
    - if: '$CI_COMMIT_BRANCH != "potato"'

只需将Mutex对象添加到您的线程并创建getter。

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();
        }
    }
}

如果您想暂停线程,只需调用

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
        }
    }
}

如果要恢复线程,只需调用

myThread.getMutex().lock();

答案 6 :(得分:0)

不推荐使用暂停和恢复线程的java原语。了解如何实现最佳效果 - http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html 检查你如何做相当于暂停& amp;恢复

  

我应该使用什么而不是Thread.suspendThread.resume

     

Thread.stop一样,谨慎的做法是让“目标线程”轮询一个变量,指示线程的所需状态(活动或暂停)。当所需状态暂停时,线程将使用Object.wait等待。当线程恢复时,使用Object.notify通知目标线程。

示例代码在相同的答案中给出,以帮助您实现此目的。