线程正在暂停,但未恢复



我对线程相当陌生,我对它们有问题。(我正在实现可运行的接口)我首先调用 start 方法,它启动线程。过了一会儿,我调用暂停方法,也可以工作。但是,当我恢复它时,我收到线程正在退出的消息。

我认为这是因为变量"暂停"

这是我的代码:

 public class Race implements Runnable {
    public Thread t = null;
    private String threadName = "Race";
    private int sleepTime = 1000; // ms Wartezeit. Wird in run eingesetzt
    private boolean suspended = false;
    public Race() {
       //Start other classes
       //Resume, Start and Pause get called from other class's ActionListener
    }
    public static void main(String[] args) {
       Race r = new Race();
    }
    @Override
    public void run() {
        int i = 0;
        //lebendig = true;
        try {
            while (!suspended) {
                //Code goes here
                Thread.sleep(sleepTime);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " + threadName + " interrupted.");
        }
        System.out.println("Thread " + threadName + " is exiting");
    }
    public void start() {
        suspended = false;
        System.out.println("Starting " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
    public void pause() {
        suspended = true;
        t = null;
    }
    synchronized void resume() {
        suspended = false;
        notify();
    }
    public void pause() {
        suspended = true;
        t = null;
    } 
}

这是我的一个项目中的示例 Runnable。 这个 Runnable 维护了一个可以启动和停止的计时器。

package com.ggl.kakurasu.runnable;
import javax.swing.SwingUtilities;
import com.ggl.kakurasu.model.KakurasuModel;
import com.ggl.kakurasu.view.KakurasuFrame;
public class ElapsedTimeRunnable implements Runnable {
    private volatile boolean running;
    private volatile boolean solved;
    private KakurasuFrame frame;
    private KakurasuModel model;
    public ElapsedTimeRunnable(KakurasuFrame frame, KakurasuModel model) {
        this.frame = frame;
        this.model = model;
        this.running = true;
        this.solved = false;
    }
    @Override
    public void run() {
        while (running) {
            long sleepTime = solved ? 500L : 5L;
            while (!solved) {
                String elapsedTimeString = model.getElapsedTime(System
                        .currentTimeMillis());
                updateControlPanel(elapsedTimeString);
                sleep(50L);
            }
            sleep(sleepTime);
        }
    }
    private void updateControlPanel(final String elapsedTimeString) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.updateControlPanel(elapsedTimeString);
            }
        });
    }
    private void sleep(long sleepTime) {
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
        }
    }
    public synchronized void setRunning(boolean running) {
        this.running = running;
    }
    public synchronized void setSolved(boolean solved) {
        this.solved = solved;
    }
}

布尔字段标记为易失性,以便可以从任何线程更改值。 设置布尔字段的方法标记为已同步,以便一次只有一个线程可以更新布尔字段。

如您所见,有 2 个布尔值用于控制 run 方法。 当我们想要完全停止 Runnable 时,正在运行的布尔值设置为 false。 我们启动包含 Runnable 的线程一次。 我们停止包含 Runnable 的线程一次。

求解的布尔值启动和停止计时器循环。 当求解的布尔值为 false 时,计时器显示每 50 毫秒更新一次,从而将显示精确到十分之一秒。

当求解的布尔值为真时,计时器停止。 外循环仍在运行。 我们休眠 500 毫秒,这样我们就不会占用大量的 CPU 时间,但代码可以在计时器再次启动时响应。

要记住的要点:一个线程只能启动一次。 一个线程只能停止一次。 如果要暂停线程,则必须在 run 方法中提供备用代码,以便线程继续运行。

我认为拥有一个 Runnable 并启动一个运行 Runnable 的线程可能会增加混乱,特别是因为您给 Race 的方法与 Thread 的方法相似(即 start()suspend()resume()尽管后两者已被弃用)。但从根本上说,问题是:

  1. 关于 Runnables 的notify()没有什么特别之处,调用通知只会解决由 wait() 发起的被阻止的代码。
  2. 只要您将 suspend 设置为 true,run() 中的 while 循环就会终止,而不是使用 wait() 阻塞。

下面的演示展示了如何编写这个Thread(避免创建额外的句柄、重写start()等),我已经使用了unpause() resume()因为这是 Thread 中的最终方法。

import java.io.PrintStream;
public class Race extends Thread {
   private PrintStream logStream = null;
   private boolean paused = false;
   private int sleepTime = 100;
   public static void main(String[] args){
      try{
         Race r = new Race("Race Thread", System.out);
         r.start();  //provided by Thread
         Thread.sleep(1000);
         r.pause();  //test
         Thread.sleep(1000);
         synchronized(r){r.notify();} //improper
         Thread.sleep(1000);
         r.unpause(); //proper
      }
      catch(Exception e){}
   }
   public Race(String name, PrintStream log){
      super(name);
      logStream = log;
   }
   public void run(){
      //runs only on assigned thread
      if(Thread.currentThread() != this)
         return;
      log("starting");
      //define parameters
      int i=0;
      //run until break
      while(true){
         //actions
         System.out.println(i++);
         //exit(optional)
         if(i==20)
            break;
         try{ Thread.sleep(sleepTime); }
         catch(InterruptedException e){}
         //WAIT LOOP ILLUSTRATION
         if(paused){
            log("pausing");
            while(true){
               try{ synchronized(this){ wait();} }
               catch(IllegalMonitorStateException e){log(e.toString());}
               catch(InterruptedException e){log(e.toString());}
               if(!paused){
                  log("resuming");
                  break;
               }
               log("falsely notified");
            }
         }
      }
      log("exiting");
   }
   public void pause(){
      if(!paused)
         paused = true;
   }
   public void unpause(){
      if(paused){
         paused = false;
         synchronized(this){ notify(); }
      }
   }
   private void log(String s){
      if(logStream!=null)
         logStream.println(getName()+" is "+s);
   }
}

请注意,要提供暂停功能,wait()命令必须处于循环状态,否则任何notify()都可能取消阻止它。此外,wait()notify()通过同步调用。

最后,我的等待循环插图比它需要的更复杂(因此它将说明另一个线程通知的潜在不当调用)。您可能可以通过以下方式获得:

while(paused){
   try{ synchronized(this){ wait();} }
   catch(IllegalMonitorStateException e){}
   catch(InterruptedException e){}
}

如果你想继续将所有东西构建为Runnable,也许要使单个进程由多个线程(按顺序)执行,那么您将需要其他小的更改。例如,run()不应该初始化你的变量,因为你启动的每个线程都会开始run()并重置数据(或者更糟糕的是,无法访问run()中声明的实例变量)。但是,您仍会以相同的方式使用等待和通知。

最新更新