我有一个线程数组,我想开始其中的一些。关键是我想在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()
的文档是(我的强调):
Returns the state of this thread. This method is designed for use in monitoring of the system state, not for synchronization control.
您正在尝试使用它进行同步,因此您已经超出了推荐范围。
如果您查看
Thread.State
,您会发现它并不总是RUNNABLE
,而且我怀疑(通常情况下)System.out
是同步的,因此尽管从您的代码中看不出来,该线程也可能是WAITING
(在另一个竞争的线程上使用System.out
)。鉴于您所有线程所做的只是锤子输出,可能很常见,一个或多个正在等待。您甚至找不到任何内容显示该对话框,因为当您遍历循环时,恰好与该线程等待时间一致!
通过读取状态并输出来检查它!
因此,首先,不要使用
getState()
进行同步,并且要注意,您并不总是知道正在使用的库中“幕后”正在进行的同步。该文档为实现者留出了可能在
getState()
的低级同步中走捷径,并且该值可能不是“一流”可靠的(同步的),但是无论什么都不做,即使您不这样做,也被告知不要这样做。不知道为什么!正确的方法是
isAlive()
。如果线程的start()
方法已调用且尚未终止,则该线程仍处于 Activity 状态。等待与否,它还活着……下一个问题是因为您在
processing=true;
方法中设置了run()
,因此您可以在stopProcessing()
设置为processing
之前调用true
。当您在主线程中到达
run()
时,无法保证该线程到达stopProcessing()
向下的距离(如果有的话)。我知道有用户交互(例如,大延迟),但是在过载(或单线程!)机器上或将来的用例中,可以在
processing=true;
将其设置为stopProcessing()
之后执行false
。这可能导致“失控”处理。因此,请在类声明中使用
volatile boolean processing=true;
或在构造函数中进行设置。这保证了它将在构造函数的末尾设置(发生在控制线程中),并且必须在调用stopProcessing()
之前进行设置。您的应用程序(当然)是一个玩具,但请考虑一下何时停止用户没有停止的线程。
不结束所有线程的安全结论而只是结束JVM是一种不好的做法。
这对您的玩具无关紧要,但在实际应用程序中,您可能希望释放外部资源和(例如)刷新文件缓冲区,而不是让JVM退出运行。
也就是说,在结束应用程序之前,最后在一个循环中在所有线程上调用
stopProcessing()
,然后在第二个循环中调用join()
。使用两个循环很重要,因为这可以确保线程全部同时停止,而不是一个接一个地停止。
我不太强调为什么您应该正确结束线程。人们常常不理我,然后长期从事开发工作,却遇到了难以定位和难以驱除的怪异故障。
其他注意事项:
考虑使用
interrupt()
。它旨在帮助终止线程,并为您做一些好事,例如使它们退出 sleep 和等待条件(带有Interrupted
异常)。这意味着它们可能比您的方法更快(永远不会更慢)终止。同样,与玩具无关,但在严肃的应用中很有值(value)。
考虑子类化
Runnable
而不是Thread
。同样,您的玩具还不错并且有效,但是“真实”应用程序最终还是更喜欢Runnable
并使用某种类型的线程池(例如ExecutorService
)。这很聪明,因为在许多平台上,创建和销毁Threads
的开销远远大于轻量级Runnable
的开销。这是标准建议,但我认为它的智慧永远不会得到解释。
关于java - 停止阵列中正在运行的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54093138/