java - 停止阵列中正在运行的线程

标签 java multithreading

我有一个线程数组,我想开始其中的一些。关键是我想在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/

相关文章:

c++ - 如何在 while 循环中使用带有中断的 openmp

C多线程嵌套for循环-超参数网格搜索的组合爆炸问题

c++ - Windows.h 线程关联

java - JDO查询返回不符合过滤条件的实体

java - AjaxLink 的 Wicket AttributeModifier

c# - Parallel.For 语句返回 "System.InvalidOperationException"带位图处理

java - 自定义谓词有时会返回随机结果

java - 在可观察项目之间添加延迟 RxJava

java - 在 Gradle 项目 IntelliJ 中激活断言

java - Android - 加载库失败