我有一个线程数组,我想开始其中的几个。关键是我想在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();
}
}
}
}
}
答案 0 :(得分:2)
getState()
的文档为(我的重点):
返回该线程的状态。此方法设计用于 监视系统状态,不用于同步控制。
您正尝试将其用于同步,因此您已超出建议范围。
如果您查看Thread.State
,您会发现它并不总是RUNNABLE
,而且我怀疑,System.out
通常是同步的,因此尽管从您的代码中看不出来,线程可能是{ {1}}(在另一个竞争的线程上使用WAITING
)。
鉴于您所有线程所做的只是锤子输出,可能很常见,一个或多个正在等待。您甚至可能找不到任何显示对话框的内容,因为在循环过程中,您恰巧与该线程等待时间一致!
通过读取状态并输出来检查它!
因此,首先,不要使用System.out
进行同步,并且要注意,您并不总是知道正在使用的库中“幕后”正在进行的同步。
该文档允许实现者在getState()
的低级同步中偷工减料,并且该值可能不是“一流”可靠的(同步的),但是无论做什么都不告诉您不要这样做即使你不知道为什么!
正确的方法是getState()
。如果线程已经调用了isAlive()
方法并且尚未终止,则该线程仍处于活动状态。等待与否,它还活着……
下一个问题是因为您在start()
方法中设置了processing=true;
,因此可以在设置run()
之前调用stopProcessing()
。
当您到达主线程中的processing
时,无法保证线程true
向下(如果有的话)到达多远。
我知道有用户交互(例如,较大的延迟),但是在过载(或单线程!)的计算机上或将来的用例中,run()
可以在stopProcessing()
设置{{1 }}。这可能导致“失控”处理。
因此在类声明中使用processing=true;
或在构造函数中进行设置。这样可以保证它将在构造函数的末尾设置(发生在控制线程中),并且必须在调用stopProcessing()
之前。
您的应用程序(当然)是一个玩具,但请考虑何时停止用户没有停止的线程。
不结束所有线程的安全结论而只是结束JVM是一种不好的做法。
这对您的玩具无关紧要,但是在实际应用程序中,您可能希望释放外部资源和(例如)刷新文件缓冲区,而不是让JVM退出运行。
也就是说,在结束应用程序之前,最后在一个循环中在所有线程上调用false
,然后在第二个循环中调用volatile boolean processing=true;
。
使用两个循环很重要,因为这样可以确保所有线程都同时停止而不是一个接一个地停止。
我不太强调为什么您应该正确结束线程。人们常常不理我,然后长期从事开发工作,出现了难以定位和难以驱除的怪异故障。
其他注意事项:
请考虑使用stopProcessing()
。它旨在帮助终止线程,并为您做一些好事,例如使它们退出睡眠和等待条件(带有stopProcessing()
异常)。这意味着它们可能比您的方法更快(永远不会更慢)终止。
再次,与玩具无关,但在严肃的应用中有价值。
考虑将join()
而不是interrupt()
子类化。同样,您的玩具还算是有效的,但是“真实的”应用程序最终还是更喜欢Interrupted
并使用某种线程池(例如Runnable
)。这很聪明,因为在许多平台上,创建和销毁Thread
的开销远远大于轻量级的Runnable
。
这是标准建议,但我认为它的智慧永远不会得到解释。
答案 1 :(得分:1)
在main
中进入循环时,线程可能尚未启动。选中Thread.State.NEW
时,它们的状态为arrayOfThreads[i].getState()
。
一个简单的解决方案是在执行循环之前等待一段时间以确保线程正在运行,或者在循环中运行while
循环以多次检查条件。
两者都是参差不齐且效率低下的,因为您不确切知道线程何时启动和运行。相反,我建议实现一种wait-notify
机制来在线程肯定正在运行时显示对话。