我对线程很新,我遇到问题。 (我正在实现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;
}
}
答案 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)。但从根本上说,问题是:
resume()
没有什么特别之处,调用notify只会解析由notify()
启动的阻止代码。wait()
中的while循环会在您将suspend设置为true时终止,而不是使用run()
阻止。以下演示显示了如何编写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。