java - 停止数组中正在运行的线程
问题描述
我有一系列线程,我想启动其中的一些。关键是我想在 for 循环中停止线程。在 for 循环中,我想检查所有线程是否正在运行,如果它们正在运行,我想被问到是否要停止它们(对话框是/否)。
问题是循环不会一直显示所有这三个启动线程的所有三个对话框。有时会出现 1 个对话框,有时会出现 3 个对话框等。
所以,我没有机会停止所有三个线程......
public class Main {
public static void main( String[] args )
{
Counter[] arrayOfThreads = new Counter[10];
for( int i = 0; i < arrayOfThreads.length; i++ )
{
arrayOfThreads[i] = new Counter( );
}
arrayOfThreads[3].start( );
arrayOfThreads[5].start( );
arrayOfThreads[2].start( );
for( int i = 0; i < arrayOfThreads.length; i++ )
{
if( arrayOfThreads[i].getState( ) == State.RUNNABLE )
{
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog( null, "Do you want to stop the theread: " + i, "Warning", dialogButton );
if( dialogResult == JOptionPane.YES_OPTION )
{
arrayOfThreads[i].stopProcessing( );
}
}
}
}
}
class Counter extends Thread
{
volatile boolean processing;
public void run( )
{
int i = 0;
processing = true;
while( processing )
{
System.out.println( " Number: " + i );
i++;
}
System.out.println( "finish" );
}
public void stopProcessing( )
{
processing = false;
}
}
编辑:
所以我想要的只是当我按下 EXIT 按钮关闭线程并在所有线程都停止时处理框架。我把第一堂课改得更清楚了。
public class Program extends Frame {
public static void main(String[] args) {
Counter[] arrayOfThreads = new Counter[10];
for (int i = 0; i < arrayOfThreads.length; i++) {
arrayOfThreads[i] = new Counter();
}
Program program = new Program(arrayOfThreads);
program.startThreeThreads(1, 4, 5);
}
private Counter[] arrayOfThreads;
private JButton stopThreads;
public Program(Counter[] arrayOfThreads) {
this.arrayOfThreads = arrayOfThreads;
stopThreads = new JButton("STOP THREADS");
closeThreadsWhenExitIsPressed();
setSize(300, 200);
setLayout(new FlowLayout());
add(stopThreads);
setVisible(true);
}
public void closeThreadsWhenExitIsPressed() {
stopThreads.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
stopRunningThreadsMethod();
dispose();
}
});
}
private void startThreeThreads(int first, int second, int third) {
for (int i = 0; i < arrayOfThreads.length; i++) {
if (i == first || i == second || i == third) {
arrayOfThreads[i].start();
continue;
}
}
}
public void stopRunningThreadsMethod() {
for (int i = 0; i < arrayOfThreads.length; i++) {
if (arrayOfThreads[i].isAlive()) {
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog(null, "Do you want to stop the theread: " + i,
"Warning", dialogButton);
if (dialogResult == JOptionPane.YES_OPTION) {
arrayOfThreads[i].stopProcessing();
}
}
}
}
}
解决方案
的文档getState()
是(我的重点):
返回此线程的状态。此方法设计用于监控系统状态,而不是用于同步控制。
您正在尝试将其用于同步,因此您已经不在推荐范围内。如果您看一下,Thread.State
您会发现它并非总是如此RUNNABLE
,而且我怀疑,正如常见的那样,System.out
它是同步的,因此尽管从您的代码中并不明显,但线程可能是WAITING
(在另一个竞争线程上使用System.out
)。鉴于您的线程所做的只是锤子输出,因此一个或多个线程可能很常见正在等待。您甚至可以发现没有显示对话框,因为当您循环时,您碰巧与该线程等待重合!通过读取状态并输出它来检查它!
所以首先,不要getState()
用于同步,并且要知道你并不总是知道你正在使用的库中“幕后”正在发生什么同步。该文档允许实施者在低级同步中偷工减料,getState()
并且该值可能不是“一流”可靠(同步),但无论如何不要做你被告知不要做的事情,即使你不这样做'不知道为什么!
正确的方法是isAlive()
。如果线程已start()
调用其方法但尚未终止,则该线程处于活动状态。等待与否,它还活着……
下一个问题,是因为您在之前可以调用processing=true;
的方法中设置了 set 。当您到达主线程时,无法保证线程已经走了多远(如果有的话) 。我知道存在用户交互(例如大延迟),但在重载(或单线程!)机器或未来用例上,可以在设置后执行。这可能会导致“失控”处理。run()
stopProcessing()
processing
true
run()
stopProcessing()
processing=true;
stopProcessing()
false
所以volatile boolean processing=true;
在类声明中使用或者在构造函数中设置。这保证了它将在构造函数的末尾设置(发生在控制线程中)并且必须在stopProcessing()
被调用之前。
您的应用程序(当然)是一个玩具,但请考虑何时停止用户没有停止的线程。
只结束 JVM 而不使所有线程都得出一个安全的结论是不好的做法。这在您的玩具中并不重要,但在实际应用程序中,您可能希望释放外部资源并(例如)刷新文件缓冲区,而不是让 JVM 拉出用完。也就是说,最后stopProcessing()
在一个循环中调用所有线程,然后join()
在结束应用程序之前在第二个循环中调用。使用两个循环很重要,因为它确保线程都同时停止,而不是一个接一个地停止。
我不能足够强调为什么你应该正确结束线程。人们经常忽略我,然后长期投入到开发中,出现了难以本地化和难以消除的奇怪故障。
其他注意事项:
考虑使用interrupt()
. 它旨在帮助终止线程并为您做一些好事,比如让它们脱离睡眠和等待条件(有一个Interrupted
例外)。这意味着它们可能会比您的方法更快(从不慢)终止。同样,与玩具无关,但在严肃的应用中很有价值。
考虑子分类Runnable
而不是Thread
. 同样,您的玩具很好且有效,但“真正的”应用程序最终还是倾向于Runnable
并使用某种类型的线程池(例如ExecutorService
)。这很聪明,因为在许多平台上,创建和销毁的开销Threads
远大于轻量级Runnable
. 这是标准建议,但我不认为它的智慧总是得到解释。
推荐阅读
- python - 如何通过拆分其中的字符串将单个列拆分为多个。-熊猫蟒蛇
- kotlin - 是否可以指示 Kotlin 编译器默认导入其他包(就像它自己的包一样)?
- c++ - 可选成员的decltype
- java - 已解析时间戳中的 Java 差异被忽略
- adsense - 折叠 Google Adsense Divs
- java - 如何在 Spring 中将 HTTP 参数与 @RequestBody 绑定
- android - RxSwift 中的 NetworkBoundResource
- c# - 如何在 RazorEngine 模板中使用 css/less 样式
- java - 滑动片段的导航(显示?)
- javascript - Jasmine:带有 Promise 返回的 callThrough 失败(Jasmine 2.x 和 Angular.io)