使用"通知()" &安培; "等待()"代替"暂停()"和"个人简历()"控制线程 [英] Using "notify()" & "wait()" instead of "suspend()" and "resume()" to control a thread

查看:278
本文介绍了使用"通知()" &安培; "等待()"代替"暂停()"和"个人简历()"控制线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解如何暂停,并在Java中恢复线程。我使用的是 Applet的实现Runnable 有2个按钮开始和停止。

I'm trying to learn how to pause and resume a thread in java. I'm using an Applet that implements Runnablehas 2 buttons "Start" and "Stop".

public void init(){
  th = new Thread(this);
  th.start();

  btn_increment = new Button("Start");
  btn_increment.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent ev){
      th.notify();
    }
  });
  add(btn_increment);

  btn_decrement = new Button("Stop");
  btn_decrement.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent ev){
      try{
        th.wait();
      } catch(InterruptedException e) {
        e.printStackTrace();
      }
    }
  });

  add(btn_decrement);                               
}

该线程的run方法:

The run method of the thread:

public void run(){
  while(true){
    repaint();
    try{
      Thread.sleep(20);
    } catch(InterruptedException e) {
      e.printStackTrace();
    }
  }
}

现在每当我试图暂停或恢复该线程将抛出一个异常:

Now whenever I try to to pause or resume the thread an exception is thrown:

异常螺纹AWT-EventQueue的-1java.lang.IllegalMonitorStateException

注:

在previous code完美地运行,如果我用的是德precated方法暂停()简历() ,但文档在使用指出通知()等待(),而不是用同步。我尝试添加同步字 的actionPerformed 方法,但它仍然抛出异常。

The previous code runs perfectly if I use the deprecated methods suspend() and resume(), but the documentation points out at using notify() and wait() instead with synchronization. I tried adding the word synchronized to the actionPerformed method, but it still throws the exception.

能否有人请解释的为什么这是不工作,如何解决同步问题?很少解释点真的有很大帮助;)

Can someone please explain WHY this isn't working and how to solve the synchronization problem? Few explanation points would really be of much help ;)

推荐答案

您误解了如何等待()的作品。调用对象不会暂停该线程;它,而不是告诉当前运行的线程等待其他事情发生。为了解释为什么,我需要备份了一下,解释一下同步实际上做。

You have misunderstood how wait() works. Calling wait on a Thread object does not pause that thread; it instead tells the currently running thread to wait for something else to happen. To explain why, I'll need to back up a bit and explain what synchronized actually does.

当你输入一个同步阻止你获得的监测的与对象相关联。例如,

When you enter a synchronized block you obtain the monitor associated with an object. For example,

synchronized(foo) {

获得与对象相关联的监视。

一旦你的显示器,没有其他的线程可以得到它,直到你退出synchronized块。这是通知进来了。

Once you have the monitor, no other threads can obtain it until you exit the synchronized block. This is where wait and notify come in.

是告诉当前运行的线程暂时释放其持有的显示器Object类的方法。这允许其他线程同步。

wait is a method on the Object class that tells the currently running thread to temporarily release the monitor it holds. This allows other threads to synchronize on foo.

foo.wait();

这线程将不会恢复,直到别人通话通知 notifyAll的(或者线程被中断)。一旦出现这种情况,该线程将尝试重新获得了,然后继续监视。请注意,如果任何其他线程都在等待获得监视器,那么他们可能会在第一次拿到 - 没有订单JVM将手伸出来锁保证。需要注意的是等待()将永远等待,如果没有人通话通知 notifyAll的。它通常是最好用的其他形式的,它接受一个超时。这个版本会醒过来的时候有人叫通知 / notifyAll的或当超时已过期。

This thread will not resume until someone else calls notify or notifyAll on foo (or the thread is interrupted). Once that happens, this thread will attempt to re-acquire the monitor for foo and then continue. Note that if any other threads are waiting to obtain the monitor then they might get in first - there is no guarantee of the order the JVM will hand out locks. Note that wait() will wait forever if no-one calls notify or notifyAll. It's usually best to use the other form of wait that takes a timeout. That version will wake up when someone calls notify/notifyAll or when the timeout has expired.

所以,你需要一个线程做的等待和不同的线程来完成的通知。无论通知必须持有他们试图等待或通知的对象监视器;这就是为什么你看到的抛出:IllegalMonitorStateException。

So, you need one thread to do the waiting and a different thread to do the notifying. Both wait and notify must hold the monitor on the object they are trying to wait on or notify; this is why you are seeing the IllegalMonitorStateException.

一个例子可以帮助你理解:

An example might help you understand:

class RepaintScheduler implements Runnable {
    private boolean paused = false;
    private final Object LOCK = new Object();

    public void run() {
        while (true) {
            synchronized(LOCK) {
                if (paused) {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    repaint();
                }
            }
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void pause() {
        synchronized(LOCK) {
            paused = true;
            LOCK.notifyAll();
        }
    }

    public void resume() {
        synchronized(LOCK) {
            paused = false;
            LOCK.notifyAll();
        }
    }
}

您的Applet code就可以做到这一点:

Your Applet code can then do this:

public void init() {
    RepaintScheduler scheduler = new RepaintScheduler();
    // Add listeners that call scheduler.pause and scheduler.resume
    btn_increment.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {
        scheduler.resume();
    }});
    btn_decrement.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {
        scheduler.pause();
    }});
    // Now start everything up
    Thread t = new Thread(scheduler);
    t.start();
}

请注意,该Applet类不关心调度程序如何暂停/简历,没有任何synchronized块。

Note that the Applet class does not care about how the scheduler pauses/resumes and does not have any synchronized blocks.

所以这里的事件可能的顺序是:

So a possible sequence of events here is:


  • 线程A开始运行重绘调度。

  • 线程A进入睡眠状态20毫秒。

  • 线程B(事件调度线程)接收点击一个按钮;来电暂停。

  • 线程B获得监视器上的锁。

  • 线程B更新'暂停'变量并调用LOCK.notifyAll。

  • 没有线程在等待锁所以没有什么有趣的发生。

  • 线程B释放在监视器上的锁。

  • 线程A被唤醒,通过其循​​环再次变。

  • 线程A获得监视器上的锁。

  • 线程A发现它应暂停,所以它调用LOCK.wait。

  • 在这一点上线程A暂停,等待有人打电话notifyAll的。线程A释放的锁定显示器。

  • 一段时间后,用户点击恢复。

  • 线程B调用scheduler.resume。

  • 线程B获得监视器上的锁。

  • 线程B更新'暂停'变量并调用LOCK.notifyAll。

  • 线程A看到'notifyAll的和醒来。它试图获取锁定显示器,但它是由线程B持有这样线程A块。

  • 线程B释放在监视器上的锁。

  • 线程A获得的监测和进行的。

这是否行得通的?

有不需要一个单独的锁变量;我已经做了,要强调的是,你是不是调用wait /通知在实例。同样,RepaintScheduler内部的逻辑是不理想的,但只是为了说明如何等待/通知也可以使用。

Having a separate LOCK variable is not required; I've done that to highlight the fact that you are not calling wait/notify on a Thread instance. Similarly, the logic inside the RepaintScheduler is not ideal but is just there to illustrate how wait/notify could be used.

这篇关于使用"通知()" &安培; "等待()"代替"暂停()"和"个人简历()"控制线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆