Java 即使在调用中断方法之后,线程也不会被中断
我有一个带有3个按钮的活动:创建、开始和取消。Button create创建一个新线程,Button start运行该线程,Button cancel停止该线程。我的问题是,调用中断方法后线程并没有中断。这个操作是在单击取消按钮后执行的。我知道,在我的线程中,我应该检查线程是否被中断。我添加了它,但中断仍然不起作用。这是我的密码:Java 即使在调用中断方法之后,线程也不会被中断,java,android,multithreading,Java,Android,Multithreading,我有一个带有3个按钮的活动:创建、开始和取消。Button create创建一个新线程,Button start运行该线程,Button cancel停止该线程。我的问题是,调用中断方法后线程并没有中断。这个操作是在单击取消按钮后执行的。我知道,在我的线程中,我应该检查线程是否被中断。我添加了它,但中断仍然不起作用。这是我的密码: private View.OnClickListener listener = new View.OnClickListener() { @Suppr
private View.OnClickListener listener = new View.OnClickListener() {
@SuppressLint("HandlerLeak")
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.create_button:
thread = new Thread(new Runnable() {
@Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
}
}, 500*i);
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
new Handler().postDelayed(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
textCounter.setText("Done!");
}
},(i+1)*500);
}
});
break;
case R.id.start_button:
thread.run();
break;
case R.id.cancel_button:
thread.interrupt();
Log.i(getClass().getSimpleName(), "Cancel Button clicked");
break;
}
}
};
那么,为什么线程没有被中断,我如何解决这个问题呢?您的线程正在快速添加11个任务10+最后一个任务到您正在创建的处理程序中,然后死亡。这些任务有一个延迟,然后消息队列将负责运行10+1可运行程序。要执行您试图执行的操作,应该使线程在每个循环之间等待500毫秒 类似于此:
thread = new Thread(new Runnable() {
@Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText("Done!");
}
});
}
});
您的线程正在快速添加11个任务,10+最后一个任务到您正在创建的处理程序中,然后死亡。这些任务有一个延迟,然后消息队列将负责运行10+1可运行程序。要执行您试图执行的操作,应该使线程在每个循环之间等待500毫秒 类似于此:
thread = new Thread(new Runnable() {
@Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText("Done!");
}
});
}
});
你的代码有很多问题 问题1:当用户单击“创建”按钮时,您创建了一个新线程,这不是您想要的预期行为,因此,如果尚未创建或终止新线程,只需创建一个新线程即可 问题2:当用户单击开始按钮时 此行并不启动线程,它只是在调用线程的run方法中执行代码,在本例中是main/UI线程。要启动线程,必须使用start方法。如果线程已创建,请确保启动该线程 问题3:当用户单击“取消”按钮时 因为没有线程启动,所以此行将不执行任何操作 问题4:根据您的描述,您希望使用线程将TextView上的计数器每0.5秒从0增加到9,然后显示“完成”。您的代码不正确,并且包含许多冗余代码 解决方案:您可以遵循以下代码
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.create_button:
// Only create a new thread if it is not created or it is terminated.
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
final int finalI = i;
// This will post a message to main/UI thread.
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
// Sleep current thread in 0.5 second before running next step.
Thread.sleep(500);
}
// Display Done after finishing counter.
textCounter.post(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
textCounter.setText("Done!");
}
});
} catch (InterruptedException e) {
// Display Cancelled if the current thread is cancelled.
textCounter.post(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
textCounter.setText("Cancelled!");
}
});
}
}
});
} else {
Toast.makeText(MainActivity.this,
"Thread is already created. No need to create anymore.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.start_button:
// Start thread if it is created.
if (thread != null && thread.getState() == Thread.State.NEW) {
thread.start();
} else {
Toast.makeText(MainActivity.this,
"Thread is not created yet or it is running.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.cancel_button:
// Cancel the thread if it is running.
if (thread != null && thread.isAlive()) {
thread.interrupt();
} else {
Toast.makeText(MainActivity.this,
"Thread is not running yet.",
Toast.LENGTH_SHORT)
.show();
}
break;
}
}
};
你的代码有很多问题 问题1:当用户单击“创建”按钮时,您创建了一个新线程,这不是您想要的预期行为,因此,如果尚未创建或终止新线程,只需创建一个新线程即可 问题2:当用户单击开始按钮时 此行并不启动线程,它只是在调用线程的run方法中执行代码,在本例中是main/UI线程。要启动线程,必须使用start方法。如果线程已创建,请确保启动该线程 问题3:当用户单击“取消”按钮时 因为没有线程启动,所以此行将不执行任何操作 问题4:根据您的描述,您希望使用线程将TextView上的计数器每0.5秒从0增加到9,然后显示“完成”。您的代码不正确,并且包含许多冗余代码 解决方案:您可以遵循以下代码
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.create_button:
// Only create a new thread if it is not created or it is terminated.
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
final int finalI = i;
// This will post a message to main/UI thread.
textCounter.post(new Runnable() {
@Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
// Sleep current thread in 0.5 second before running next step.
Thread.sleep(500);
}
// Display Done after finishing counter.
textCounter.post(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
textCounter.setText("Done!");
}
});
} catch (InterruptedException e) {
// Display Cancelled if the current thread is cancelled.
textCounter.post(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
textCounter.setText("Cancelled!");
}
});
}
}
});
} else {
Toast.makeText(MainActivity.this,
"Thread is already created. No need to create anymore.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.start_button:
// Start thread if it is created.
if (thread != null && thread.getState() == Thread.State.NEW) {
thread.start();
} else {
Toast.makeText(MainActivity.this,
"Thread is not created yet or it is running.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.cancel_button:
// Cancel the thread if it is running.
if (thread != null && thread.isAlive()) {
thread.interrupt();
} else {
Toast.makeText(MainActivity.this,
"Thread is not running yet.",
Toast.LENGTH_SHORT)
.show();
}
break;
}
}
};
为什么要投否决票?即使这段代码很难看,但基本上是在做问题作者所问的事情。当然,有更好的方法可以做到这一点。这是正确的答案,我只想补充一点,isInterrupted返回false,因为线程在终止后很久就被中断了,在这种情况下,isInterrupted的设计行为是返回false。为什么要投否决票?即使这段代码很难看,但基本上是在做问题作者所问的事情。当然,还有更好的方法。这是正确的答案,我只想补充一点,isInterrupted返回false,因为线程在终止后很久就被中断了,在这种情况下,isInterrupted的设计行为,是返回false。@XavierRubioJansana正确识别了您的问题-作为他的解决方案的替代方案,您还可以通过调用其RemoveCallback来取消任何未完成的延迟处理程序。为此,您需要在cancel案例中引用每个处理程序。查看并遵循该答案中的任何链接。@XavierRubioJansana正确识别了您的问题-作为他的解决方案的替代方案,您还可以通过调用其RemoveCallback来取消任何未完成的延迟处理程序。为此,您需要在cancel案例中引用每个处理程序。查看并遵循该答案中的任何链接。没有注意到问题2,捕捉良好。我专注于延迟的问题,最终没有注意到。顺便说一句@sergei mikhailovskii这是线程的一个非常常见的错误。另外,全局try-catch(而不是同时检查isInterrupted和捕获异常)似乎是一个很好的折衷方法,可以简化一点代码。我专注于延迟的问题,最终没有注意到。顺便说一句@sergei mikhailovskii这是线程的一个非常常见的错误。另外,一个全局try-catch(而不是同时检查isInterrupted和捕获异常)看起来像 这里有一个很好的例子,可以简化一点代码。