我对线程相当陌生,我对它们有问题。(我正在实现可运行的接口)我首先调用 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()
尽管后两者已被弃用)。但从根本上说,问题是:
- 关于 Runnables 的
notify()
没有什么特别之处,调用通知只会解决由wait()
发起的被阻止的代码。 - 只要您将 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()
中声明的实例变量)。但是,您仍会以相同的方式使用等待和通知。