2013-06-04 1 views
1

Я только начал с резьбы. Я написал главный класс, который устанавливает и запускает 100 потоков, ждет 5 секунд, а затем прерывает их (по крайней мере, это то, что я думал, что это сделало):Как (надежно) прерывать потоки из основного потока через определенное количество времени в Java?

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."); 
} 

Нить выглядела немного так:

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; 
      } 
     } 
    } 
} 

Теперь я получил то, что основной поток начал прерывать потоки, но некоторые подпотоки продолжали работать несколько раз (т.е. итерации цикла) до завершения, например

Стартовые темы ...
Thread-1: 0
резьбы 2: 0
Thread-1: 1
резьбы 3: 0
[...]
Время вверх - Концевые нити ...
...... тема-1: 60
резьбы 1: 61
... тема-1: 62
резьбы 2: 55
..All сделано.
[выход из нитей иногда продолжались даже здесь - после того, как присоединиться()]

В то время я не в полной мере понять, что один поток может быть выделено достаточное количество процессорного времени, чтобы запустить несколько раз - я ожидал максимум один дополнительный прогон перед тем, как основной поток имел возможность прервать его.

Но, хотя теперь я вижу, что это нормально для потока, выполняемого в течение некоторого (длинного) времени, прежде чем основной поток получит шанс прекратить (то есть прервать) его, мне все еще интересно: есть ли easy Способ прерывания всех дочерних потоков своевременно из основного потока? (Установка «времени на живое» через конструктор потока, а затем тестирование внутри класса Walker для него не то, что я хочу.)

Также: возможно ли выполнить последний оператор печати, а затем просмотреть некоторые результаты из отдельные потоки - после того, как все потоки присоединились() ed? (Может быть, у меня есть глюк где-то еще, фактический код является немного более сложным ...)

ответ

1

Проблема вы наблюдаете, вероятно, благодаря тому, как System.out.println работ.Это синхронизированный метод. Таким образом, вероятное объяснение:

  • при вызове System.out.print("."); после t.interrupt();, ваш основной поток получает блокировку для печати
  • до снятия блокировки, рабочие потоки прибывают в System.out.println(Thread.currentThread().getName() + ":" + i); и ждать замка
  • когда основной поток освобождает блокировку, все рабочие потоки, которые ожидали, печатают свой прогресс.
  • основной поток поступает в System.out.print("."); снова и должен ждать блокировки печати будет доступна и т.д.

Что касается того, что вы видите больше отпечатков из рабочих потоков после "All Done" распечатывается: вы только join в течение 10 мс, поэтому возможно, что этого недостаточно, и поток не завершен в течение 10 мс прерывания. Если вы просто используете join(), вы не должны этого больше видеть.

Пример класса 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; 
      } 
     } 
    } 
} 
0
Maybe I have a glitch somewhere else; the actual code is a bit more complex... 

Да это глюк, к сожалению, это не просто набор 1 свойство, ява сторона.

Если код коммерческий, сложный, вы можете выделить немного времени для написания некоторых родных библиотек для основного типа Os. С этой помощью вы можете легко играть с нитками, как вы хотели.

Первых времен есть накладный расходы на разработку и понимания того, как нити WOKING в нативной стороне зева, чем просто вызвать функцию с несколько Params :)

Не уверен, если помогает, глюк существует ,

2

Было бы проще с 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(); 
+0

Спасибо, я буду идти на это. :) – Christian

Смежные вопросы