首页 > 解决方案 > 停止数组中正在运行的线程

问题描述

我有一系列线程,我想启动其中的一些。关键是我想在 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();
                }
            }
        }
    }

}

标签: javamultithreading

解决方案


的文档getState()是(我的重点):

返回此线程的状态。此方法设计用于监控系统状态,而不是用于同步控制

您正在尝试将其用于同步,因此您已经不在推荐范围内。如果您看一下,Thread.State您会发现它并非总是如此RUNNABLE,而且我怀疑,正如常见的那样,System.out它是同步的,因此尽管从您的代码中并不明显,但线程可能是WAITING(在另一个竞争线程上使用System.out)。鉴于您的线程所做的只是锤子输出,因此一个或多个线程可能很常见正在等待。您甚至可以发现没有显示对话框,因为当您循环时,您碰巧与该线程等待重合!通过读取状态并输出它来检查它!

所以首先,不要getState()用于同步,并且要知道你并不总是知道你正在使用的库中“幕后”正在发生什么同步。该文档允许实施者在低级同步中偷工减料,getState()并且该值可能不是“一流”可靠(同步),但无论如何不要做你被告知不要做的事情,即使你不这样做'不知道为什么!

正确的方法是isAlive()。如果线程已start()调用其方法但尚未终止,则该线程处于活动状态。等待与否,它还活着……

下一个问题,是因为您在之前可以调用processing=true;的方法中设置了 set 。当您到达主线程时,无法保证线程已经走了多远(如果有的话) 。我知道存在用户交互(例如大延迟),但在重载(或单线程!)机器或未来用例上,可以在设置后执行。这可能会导致“失控”处理。run()stopProcessing()processingtruerun()stopProcessing()processing=true;stopProcessing()false

所以volatile boolean processing=true;在类声明中使用或者在构造函数中设置。这保证了它将在构造函数的末尾设置(发生在控制线程中)并且必须在stopProcessing()被调用之前。

您的应用程序(当然)是一个玩具,但请考虑何时停止用户没有停止的线程。

只结束 JVM 而不使所有线程都得出一个安全的结论是不好的做法。这在您的玩具中并不重要,但在实际应用程序中,您可能希望释放外部资源并(例如)刷新文件缓冲区,而不是让 JVM 拉出用完。也就是说,最后stopProcessing()在一个循环中调用所有线程,然后join()在结束应用程序之前在第二个循环中调用。使用两个循环很重要,因为它确保线程都同时停止,而不是一个接一个地停止。

我不能足够强调为什么你应该正确结束线程。人们经常忽略我,然后长期投入到开发中,出现了难以本地化和难以消除的奇怪故障。

其他注意事项:

考虑使用interrupt(). 它旨在帮助终止线程并为您做一些好事,比如让它们脱离睡眠和等待条件(有一个Interrupted例外)。这意味着它们可能会比您的方法更快(从不慢)终止。同样,与玩具无关,但在严肃的应用中很有价值。

考虑子分类Runnable而不是Thread. 同样,您的玩具很好且有效,但“真正的”应用程序最终还是倾向于Runnable并使用某种类型的线程池(例如ExecutorService)。这很聪明,因为在许多平台上,创建和销毁的开销Threads远大于轻量级Runnable. 这是标准建议,但我不认为它的智慧总是得到解释。


推荐阅读