代码之家  ›  专栏  ›  技术社区  ›  Roman

这是一个好的方法来关闭一个线程?

  •  -1
  • Roman  · 技术社区  · 15 年前

    我有一个简短的问题:

    1. 我开始写这样一个帖子: counter.start(); 在哪里 counter 是一个线程。
    2. 当我想停止线程时,我会这样做: counter.interrupt()
    3. 在我的线程中,我定期执行以下检查: Thread.interrupted() . 如果给予 true return 从线程,因此,它停止。

    下面是一些细节,如果需要的话:

    如果你需要更多的细节,他们在这里。从invent dispatch线程开始,我以这种方式启动一个计数器线程:

    public static void start() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                showGUI();
                counter.start();
            }
        });
    }
    

    其中线程的定义如下:

    public static Thread counter = new Thread() {
        public void run() {
            for (int i=4; i>0; i=i-1) {
                updateGUI(i,label);
                try {Thread.sleep(1000);} catch(InterruptedException e) {};
            }
                // The time for the partner selection is over.
            SwingUtilities.invokeLater(new Runnable() {
                    public void run() {    
                    frame.remove(partnerSelectionPanel);
                    frame.add(selectionFinishedPanel);
                    frame.invalidate();
                    frame.validate();
                }
            });
        }
    };
    

    线程在“第一个”窗口中执行倒计时(它显示了还剩很多时间)。如果超过时间限制,线程将关闭“第一个”窗口并生成一个新窗口。我想用以下方式修改我的线程:

    public static Thread counter = new Thread() {
        public void run() {
            for (int i=4; i>0; i=i-1) {
                if (!Thread.interrupted()) {
                    updateGUI(i,label);
                } else {
                    return;
                }
                try {Thread.sleep(1000);} catch(InterruptedException e) {};
            }
            // The time for the partner selection is over.
            if (!Thread.interrupted()) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {    
                    frame.remove(partnerSelectionPanel);
                    frame.add(selectionFinishedPanel);
                    frame.invalidate();
                    frame.validate();
                }
            });
            } else {
                return;
            } 
        }
    };
    

    补充:

    因为某些原因它不起作用。我有一个中断线程的方法:

    public static void partnerSelected() {
        System.out.println("The button is pressed!!!!");
        counter.interrupt();
    }
    

    此方法在按下按钮时激活。当我按下按钮时,我看到终端中相应的输出(所以这个方法被激活,它会做一些事情)。但由于某些原因,它不会中断线程。以下是线程的代码:

    public static Thread counter = new Thread() {
        public void run() {
            for (int i=40; i>0; i=i-1) {
                    if (Thread.interrupted()) {
                        System.out.println("Helloo!!!!!!!!!!!!!!!");
                        return;
                    }
                updateGUI(i,label); 
                try {Thread.sleep(1000);} catch(InterruptedException e) {};
            }
                // The time for the partner selection is over.
                if (Thread.interrupted()) {
                    System.out.println("Helloo!!!!!!!!!!!!!!!");
                    return;
                }
            SwingUtilities.invokeLater(new Runnable() {
                    public void run() {    
                    frame.remove(partnerSelectionPanel);
                    frame.add(selectionFinishedPanel);
                    frame.invalidate();
                    frame.validate();
                }
            });
        }
    };
    

    我看不到“你好!!!!!!!!!!!!!!!!!在终点站…

    5 回复  |  直到 15 年前
        1
  •  5
  •   C. K. Young    15 年前

    非常接近正确的想法。但是,在你的 catch (InterruptedException) 你应该有:

    Thread.currentThread().interrupt();
    

    这样中断的状态会再次继续,而不会在第二个块中执行任务。


    编辑以使我的观点更清楚(因为op的编辑似乎遗漏了我的初始点:-p):您应该这样编写代码:

    try {
        for (int = 40; i > 0; --i) {
            updateGUI(i, label);
            Thread.sleep(1000);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();  // <-- THIS LINE IS IMPORTANT
    }
    

    第二次编辑解释什么是中断。-)

    当你打电话 thread.interrupt() ,那条线 中断标志 被设置。这个旗子本身什么也做不了,它只是一个变量。这是因为中断支持所谓的“协作线程管理”,即线程的运行代码决定中断时要做什么(而不是被迫当场退出)。

    JDK中内置的一些函数,如 Thread.sleep Object.wait Lock.lockInterruptibly 威尔 检查 旗子,如果它被设置好了,它就会抛出一个 InterruptedException 在清除旗帜之后。

    所以,如果调用其中一个函数,就不需要手动检查中断标志。但是如果你没有,例如,如果你正在做密集的处理而不是等待,那么你应该定期检查标志。

    检查标志有两种方法:

    1. interrupted()
    2. isInterrupted()

    第一个清除中断标志,第二个不清除。您必须决定哪个版本对您的应用程序逻辑“更正确”。

        2
  •  1
  •   Brian Agnew    15 年前

    看看这篇文章 JavaSpecialists 新闻稿,包括如何 interrupt() 线程并正确管理。

        3
  •  0
  •   Midhat    15 年前

    是的,这是条路

        4
  •  0
  •   Roman    15 年前
    1. 这被认为是更好的方法( link )为此目的使用单独的易失性变量(布尔型IsStop)。

    2. 假定 interrupted() 如果线程被中断,方法将值从true更改为false,即:

    System.out.println (Thread.interrupted()); //true

    system.out.println(thread.interrupted());//false

    另一种选择是 isInterrupted() 方法。

        5
  •  0
  •   Ricket    15 年前

    我想编辑并注意到我今天在这里学到了一个教训。正如我在下面两段中所解释的那样,没有理由实现布尔值;中断机制为我做到了这一点。出于某种原因,我假设“中断”会使线程停止运行(我不知道当时我认为isInterrupted()做了什么!).

    所以, 这里有一个不该做的例子。 继续使用你的中断技巧!

    (请不要轻视我…)


    我倾向于避免打断别人,但特别是打断别人的话。在您的例子中,您正试图使用interrupt()作为stop()的替代方法,stop()已被出于正当理由而弃用。您只需要声明一个布尔值,它表示线程是否应该停止计数,并让线程连续检查该布尔值。然后,当父线程准备好让计数器停止时,它应该将布尔值设置为true(stop),这将导致计数器线程在再次检查该值时立即停止。

    在计数器线程的匿名类定义中,添加 public volatile boolean shouldStop; . 开始的时候 run() ,集合 shouldStop = false; . 然后全部替换 Thread.interrupted() 具有 shouldStop (在你的 if 声明)。最后,不是打电话 counter.interrupt() 只是说 counter.shouldStop = true; . 你可以另外打电话 counter.join() 设置后立即 shouldStop=true 如果要确保计数器在继续之前已停止。