线程暂停但没有恢复

时间:2016-01-21 17:10:41

标签: java multithreading

我对线程很新,我遇到问题。 (我正在实现runnable接口) 我首先调用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;
    } 
}

2 个答案:

答案 0 :(得分:1)

这是我的一个项目中的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;
    }

}

布尔字段标记为volatile,以便可以从任何线程更改值。设置布尔字段的方法被标记为synchronized,因此一次只有一个线程可以更新布尔字段。

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

已解决的布尔值启动并停止计时器循环。当解决的布尔值为假时,定时器显示每50毫秒更新一次,这样可以准确显示十分之一秒。

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

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

答案 1 :(得分:1)

我认为有一个Runnable并且启动一个运行所述Runnable的Thread可能会增加混乱,特别是因为你给Race的方法类似于Thread的方法(即start(),{{1} }和suspend()虽然the latter two are deprecated)。但从根本上说,问题是:

  1. 关于Runnables的resume()没有什么特别之处,调用notify只会解析由notify()启动的阻止代码。
  2. wait()中的while循环会在您将suspend设置为true时终止,而不是使用run()阻止。
  3. 以下演示显示了如何编写wait()(避免创建额外句柄,重写Thread等)并且我已使用start(),因为{{ 1}}是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 Loop插图比它需要的更复杂(因此它将说明另一个线程通知的潜在不正确的调用)。你可以接受:

    wait()

    如果你想继续将所有内容构建为notify(),也许是为了让一个进程由多个线程(顺序)执行,那么你需要进行其他小的改动。例如,while(paused){ try{ synchronized(this){ wait();} } catch(IllegalMonitorStateException e){} catch(InterruptedException e){} } 不应该初始化变量,因为您启动的每个Thread都将开始Runnable并重置数据(或者更糟糕的是,无法访问run()中声明的实例变量)。但是,您仍然会以相同的方式使用wait和notify。