简体   繁体   English

如何(可靠地)在Java中的特定时间后中断线程形成主线程?

[英]How to (reliably) interrupt threads form the main thread after a specific amount of time in Java?

I just started out with threading. 我刚刚开始使用线程。 I wrote a main class that sets up and starts 100 threads, waits 5 seconds and then interrupts them (at least that's what I thought it did): 我写了一个主类,设置并启动100个线程,等待5秒,然后中断它们(至少这是我认为它做的):

public static void main(String[] args) {

    List<Thread> threads = new ArrayList<Thread>();

    for (int i = 0; i < 100; i++) {
        Thread t = new Thread(new Walker());
        threads.add(t);
    }

    System.out.println("Starting threads...");

    for (Thread thread : threads) {
        thread.start();
    }

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        // don't do anything
    }

    System.out.println("Time's up - Terminating threads...");
    for (Thread t : threads) {
        t.interrupt();
        System.out.print(".");
    }
    for (Thread t : threads) {
        try {
            t.join(10);
        } catch (InterruptedException e) {
            // don't do anything
        }
    }
    System.out.println("");
    System.out.println("All done.");
}

The threads looked a bit like this: 线程看起来有点像这样:

public class Walker implements Runnable {
    public void run() {
        for (int i = 0;; i++) {
            //do some complicated stuff that takes some time
            System.out.println(Thread.currentThread().getName() + ":" + i);
            if (Thread.interrupted()) {
                break;
            }
        }
    }
}

Now, the output I got was that the main thread began interrupting threads, but some sub threads continued to run a few times (ie loop iterations) before terminating, eg 现在,我得到的输出是主线程开始中断线程,但是一些子线程在终止之前继续运行几次(即循环迭代),例如

Starting threads... 开始线程......
Thread-1:0 线程1:0
Thread-2:0 线程2:0
Thread-1:1 线程1:1
Thread-3:0 线程3:0
[...] [...]
Time's up - Terminating threads... 时间到了 - 终止线程......
......Thread-1:60 ......线程1:60
Thread-1:61 线程1:61
...Thread-1:62 ...线程1:62
Thread-2:55 线程2:55
..All done. ..全部做完。
[output from threads sometimes continued even here - after the join()] [线程的输出有时会在这里继续 - 在join()之后]

At that time I didn't fully understand that a single thread could be allocated enough processor time to run a few times - I expected at most one additional run before the main thread had the opportunity to interrupt it. 当时我并没有完全理解单个线程可以分配足够的处理器时间来运行几次 - 在主线程有机会中断它之前,我预计最多会有一次额外的运行。

But while I now see that it is absolutely fine for a thread to be executed for some (long) time before the main thread gets a chance to terminate (ie interrupt) it, I am still wondering: is there an easy way to interrupt all child threads in a timely manner from the main thread? 但是,虽然我现在看到一个线程在主线程有机会终止(即中断)它之前执行了一段时间(但很长时间),我仍然想知道:是否有一种简单的方法可以中断所有线程子线程从主线程及时? (Setting a "time to live" through a thread's constructor and then testing inside the Walker class for it is not what I want.) (通过线程的构造函数设置“生存时间”,然后在Walker类中测试它不是我想要的。)

Also: is it possible for the last print statement to execute and then see some output from individual threads - after all threads were join()ed? 另外:是否有可能执行最后一个print语句,然后查看各个线程的一些输出 - 在所有线程都加入()之后? (Maybe I have a glitch somewhere else; the actual code is a bit more complex...) (也许我在其他地方有一个小故障;实际的代码有点复杂......)

It would be easier with ExecutorService, eg 使用ExecutorService会更容易,例如

    int nThreads = 100;
    ExecutorService ex = Executors.newFixedThreadPool(nThreads);
    for (int i = 0; i < nThreads; i++) {
        ex.execute(new Walker());
    }
    Thread.sleep(5000);
    ex.shutdownNow();

The problem you observe is probably due to how System.out.println works. 您观察到的问题可能是由于System.out.println工作原理。 It is a synchronized method. 这是一种同步方法。 So a likely explanation is: 所以可能的解释是:

  • when calling System.out.print("."); 在调用System.out.print("."); after t.interrupt(); t.interrupt(); , your main thread acquires the lock to print ,你的主线程获取要打印的锁
  • before the lock is released, worker threads arrive at System.out.println(Thread.currentThread().getName() + ":" + i); 在释放锁之前,工作线程到达System.out.println(Thread.currentThread().getName() + ":" + i); and wait for the lock 并等待锁定
  • when the main thread releases the lock, all the worker threads that were waiting print their progress. 当主线程释放锁时,所有正在等待的工作线程打印它们的进度。
  • the main thread arrives at System.out.print("."); 主线程到达System.out.print("."); again and has to wait for the print lock to be available, etc. 再次,必须等待打印锁可用等。

Regarding the fact that you see more prints from the worker threads after "All Done" is printed: you only join for 10 ms, so it is possible that it is not enough and a thread is not finished within 10ms of being interrupted. 关于在打印"All Done"之后您看到来自工作线程的更多打印的事实:您只join 10 ms,因此可能它不够并且线程在被中断的10ms内没有完成。 If you just use join() you should not see that any longer. 如果你只是使用join()你就不应该再看到它了。

Example of Worker class that reproduces the behaviour you observe: 再现您观察到的行为的Worker类示例:

class Walker implements Runnable {

    public void run() {
        for (int i = 0;; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                //do not respond to interruption too quickly on purpose
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {}
                Thread.currentThread().interrupt();
            }
            System.out.println(Thread.currentThread().getName() + ":" + i);
            if (Thread.interrupted()) {
                break;
            }
        }
    }
}
Maybe I have a glitch somewhere else; the actual code is a bit more complex...

Yes it is a glitch, unfortunately isn't a simple set 1 property, java side. 是的,这是一个小故障,遗憾的是不是简单的设置1属性,java方面。

If the code is commercial, complex, than you can allocate a bit more time to write some native libraries, for major Os type. 如果代码是商业的,复杂的,那么你可以为主要的Os类型分配更多的时间来编写一些本机库。 With that help you can easily play with threads as you wanted. 有了这些帮助,您可以轻松地根据需要使用线程。

The first times has an overhead for developing and understanding how the threads are woking in native, os side, than just call a function with a few params :) 第一次有开发和理解线程如何在本机,os方面进行woking的开销,而不仅仅是用几个参数调用一个函数:)

Not sure, if is helping, the glitch exists. 不确定,如果有帮助,毛刺存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM