2012-08-01 5 views
1

이것은 인터럽트를 사용하여 스레드를 종료/종료하고 Ctrl-c로 처리하는 두 번째 게시물입니다. 나는 그것을 이해하고 있는지 모르겠지만 여기에 최선의 시도가있다. 개념에 대한 명확한 설명이 필요하며 코드 예제를 제공하십시오.Threads Java Inturrupts

메인 클래스 Quitit과 다른 클래스 이 있습니다.입니다. 메인 클래스.

터미널 (Linux의 경우)를 통해 프로그램을로드 할 때 :

자바 -jar Quitit.jar

당신 Ctrl 키-C는 내가 그 말에 수정입니다 닫습니다 때 다음을 수행해야합니다.

Runtime.getRuntime() addShutdownHook()를

스레드가 종료 될 때 종료되도록 스레드.

  1. 어떻게 해결할 수 있습니까?
  2. 정상적으로 닫힐 수 있도록 메소드를 호출 할 수없는 이유는 무엇입니까?

Ctrl-C를 사용하여 종료하지 않고 Thread.Interrupt()를 통해이를 수행하려는 경우 아래 프로그램에서 올바르게 사용합니까?

  • Thread.Join()이 계속 진행하기 전에 대상 스레드가 죽을 때까지 호출 스레드를 중단합니다.
  • 어떻게 구현/호출합니까? Runtime.getRuntime(). addShutdownHook()에 Runnable 스레드를 구현하는 대신 스레드를 확장 하시겠습니까?

Quitit 클래스 :

public class Quitit extends Thread { 

    public Quitit(String name) { 
     try { 
      connect("sdfsd"); 
     } catch (Exception ex) { 

     } 
    } 

    void connect(String portName) throws Exception { 
     Thread thh = new thething("blaghname"); 
     Runtime.getRuntime().addShutdownHook(thh); 
     thh.start(); 
     System.out.println("Thread Thh (thething) Started()"); 

     while (true) { 
      try { 
       Thread.sleep(2000); 

       if (thh.isAlive()) { 
        System.out.println("Thread Thh (thething) isAlive"); 
        if (thh.isInterrupted()) { 

         System.out.println("Thread Thh (thething) is Inturrupted Should be Shutting Down"); 

        } else { 
         System.out.println("Thread Thh (thething) is Not Inturrupted"); 
         thh.interrupt(); 
         System.out.println("Thread Thh (thething) Inturrput Sent"); 
         System.out.println("Thread Thh (thething) Joined()"); 
         thh.join(); 

        } 

       } else { 
        System.out.println("Thread Thh (thething) isDead"); 
        System.out.println("Main Thread:: can now end After Sleep off 2 seconds"); 
        Thread.sleep(2000); 
        System.out.println("MMain Thread:: Sleep Ended Calling Break"); 
        break; 
       } 

      } catch (InterruptedException xa) { 
       System.out.println("Main Thread:: ending due to InterruptException second Break called"); 
       break; 
      } 
     } 

     System.out.println("Main Thread:: Outside While(true) via Break call"); 
    } 

    public static void main(String[] args) { 
     try { 

      Thread oop = new Quitit(""); 
      Runtime.getRuntime().addShutdownHook(oop); 
      oop.start(); 

     } catch (Exception ezx) { 
      System.out.println("Main Thread:: Not Expected Exception"); 
     } 
    } 
} 

TheThing 클래스 :

public class thething extends Thread { 

    thething(String name) { 
     super(name); 
    } 

    @Override 
    public void run() { 

     while (true) { 
      try { 
       System.out.println("thething class:: Inside while(true) Loop, now sleeping for 2 seconds"); 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
       try { 

        System.out.println("thething class:: has been Inturrupted now sleeping for 2 seconds!!"); 
        Thread.sleep(2000); 
        break; // Will Quit the While(true) Loop 
       } catch (InterruptedException ex) { 
        System.out.println("thething class:: Second InterruptedException called !!"); 
       } 
      } 
     } 

     System.out.println("thething class:: Outside while(true) and now thread is dying"); 
    } 
} 

출력 ::

run: 
Thread Thh (thething) Started() 
thething class:: Inside while(true) Loop, now sleeping for 2 seconds 
Thread Thh (thething) isAlive 
Thread Thh (thething) is Not Inturrupted 
Thread Thh (thething) Inturrput Sent 
Thread Thh (thething) Joined() 
thething class:: has been Inturrupted now sleeping for 2 seconds!! 
thething class:: Outside while(true) and now thread is dying 
Thread Thh (thething) isDead 
Main Thread:: can now end After Sleep off 2 seconds 
MMain Thread:: Sleep Ended Calling Break 
Main Thread:: Outside While(true) via Break call 
FINISHED - BUILD SUCCESSFUL (total time: 8 seconds) 
+1

'Quitit' 생성자에서'super()'를 호출해야합니다. – artbristol

+0

Ok 이것은 쓰레드를 죽이는 올바른 방법이 interrupt()가 아니기 때문에 다시 혼란 스럽습니다. while (true)/while (false) 루프를 제어하고 스레드가 종료되도록하는 부울 플래그를 사용하여 스레드를 종료해야합니다. 인터럽트는 프로그램을 무기한 보관할 수있는 제한 시간없이 Read()를 할 수있는 직렬 포트 read() (IO Reads)와 같은 대기 상태가있는 경우에만 사용해야합니다. 투명도가 정말 실종 된 것처럼 보입니까, 아니면 나입니까? – DevilCode

+0

@DevilCode : 인터럽트는 스레드에게 중지를 요청하는 올바른 방법입니다. 추가 플래그 필요 없음 : 인터럽트 상태가이를 수행 할 수 있습니다. –

답변

4

나는 control-c가 프로그램을 죽이지 않는다는 것에 놀랐다. 그것은 내 테스트 프로그램에서 수행하며 대부분의 유닉스 변종에 속해야한다.

닫을 때 Ctrl-c를 눌러 종료 할 때 스레드가 종료되도록해야합니다 (종료 훅 설정).

아니요, 이것은 이 아니며이 아닙니다. 종료 훅은 일부 처리를 명시 적으로 정리할 때 사용됩니다. 그들은 실행중인 스레드와 관련이 없으며 종료 방법을 설명합니다.

정상적으로 닫힐 수 있도록 메소드를 호출 할 수없는 이유는 무엇입니까?

그것은 그것이 직업이 아니기 때문에.

어떻게 해결할 수 있습니까?

나는 "그"가 무엇인지 잘 모르겠습니다. 다른 사람들이 언급했듯이 JVM은 마지막 비 데몬 스레드가 끝날 때 완료됩니다. 이 시점에서 JVM은 모든 데몬 스레드를 종료하고 종료합니다. 당신이 volatile boolean를 사용하거나 스레드를 중단 할 수 있습니다 깨끗하게 한 다음 스레드를 종료하는 적절한 방법에 대해 물어 경우

Thething theThing = new TheThing(); 
// set it to be a daemon thread before it starts 
theThing.setDaemon(true); 
theThing.start(); 

: 당신이 원하는 경우 백그라운드 스레드는 다음과 같은 일을 할 거라고 종료에 사망한다 .일반적으로 이는 스레드를 시작하는 클래스가 핸들을 유지한다는 것을 의미합니다. QuitItTheThing 클래스를 시작하기 때문에 그것이 volatile boolean 사용하는 경우는 다음과 같은 일을 할 것입니다 :

public class TheThing extends Thread { 
    volatile boolean shutdown = false; 
    public void run() { 
     while (!shutdown) { 
      ... 
      // you can also test for shutdown while processing 
      if (shutdown) { 
      return; 
      } 
     } 
    } 
} 

: TheThing에 다음

void connect(String portName) throws Exception { 
    Thread thh = new TheThing("blaghname"); 
    thh.start(); 
    ... 
    // we are ready to kill the thread now 
    tth.shutdown = true; 
} 

을의 run() 방법은 다음과 같은 일을 할 것입니다 Ctrl-C를 사용하여 종료하지 않고 Thread.interrupt()을 통해이 프로그램을 올바르게 사용 하시겠습니까?

Thread.interrupt()을 사용하면 스레드 종료 신호를 보낼 수있는 또 다른 방법입니다. 또한 위의 부울 유사한 방식으로 스레드 인터럽트 플래그를 사용할 수 있습니다 : 그것은 매우 중요합니다

void connect(String portName) throws Exception { 
    Thread thh = new TheThing("blaghname"); 
    thh.start(); 
    ... 
    // we are ready to interrupt the thread now 
    tth.interrupt(); 
} 

스레드를 중단하면 Thread에 플래그를 설정 것을 깨닫게. 스레드는 여전히 코드로 적절하게 인터럽트를 처리해야합니다. 그런 다음 TheThing에서 run() 방법은 다음과 같이 할 것 : 중단

public class TheThing extends Thread { 
    public void run() { 
     while (!Thread.currentThread().interrupted()) { 
      ... 
     } 
    } 
} 

을 또한 wait(), notify()을 초래하고 다른 방법 InterruptedException을 던져. 이 다루는 적절한 방법입니다 : 내가 대상 스레드가 계속하기 전에 사망 할 때까지를 Thread.join()를 호출 스레드를 중단한다는 말에 수정

try { 
    Thread.sleep(1000); 
} catch (InterruptedException e) { 
    // catching the interrupted exception clears the interrupt flag, 
    // so we need to re-enable it 
    Thread.currentThread().interrupt(); 
    // probably you want to stop the thread if it is interrupted 
    return; 
} 

건가요?

예. join() (인수 없음)을 호출하면 스레드가 종료 될 때까지 호출 스레드가 일시 중지됩니다. 그래서 일반적으로 당신은 당신의 종료 플래그를 설정하거나 스레드를 중단하고 다음과 조인

tth.shutdown = true; 
// or tth.interrupt() 
tth.join(); 
당신이 구현하는 것이 어떻게

/같은 Runtime.getRuntime()를 호출 구현의 Runnable 스레드 addShutdownHook() 대신. 스레드 확장?

이 질문은 의미가 없습니다. Runnable을 구현 한 경우 스레드를 종료하는 방법에 대해 묻는다면 위에서 언급 한 것과 동일한 메커니즘이 작동합니다.


control-c에 대한 논의의 또 다른 요인은 신호 처리기입니다. 그들은 control-c (및 다른 신호)를 잡아서 지능적으로 할 수 있습니다. 그것들은 매우 OS 의존적입니다. 그리고 인터럽트 신호를 받으면 (보통 SIGINT는 control-c에 의해 보내집니다) JVM을 멈추지 않으면 문제가 발생할 것입니다. 나는 아래로 JVM을 인터럽트 신호 (제어-C)를 캐치하지 나쁜 관행이라고 말할 것입니다, 다시

... 
MyHandler handler = new MyHandler(); 
// catch the control-c signal, "TERM" is another common kill signal 
Signal.handle(new Signal("INT"), handler); 
... 

private static class MyHandler implements SignalHandler { 
    @Override 
    public void handle(Signal arg0) { 
     // interrupt your threads 
     // clean up stuff 
     // set shutdown flags 
     // ... 
    } 
} 

:

그러나 어떤 경우에

, 당신은 다음과 같은 일을 할 수 있습니다 .

2

당신은 당신의 질문에 많은 질문이 있습니다. Ctrl-C가 눌 렸을 때 정상적으로 스레드를 종료하려면 종료 훅을 등록하고이 셧다운 훅의 코드에서 스레드를 정상적으로 종료하십시오.

Thread 인스턴스는 Thread를 확장하거나 Runnable을 Thread 생성자에 전달하여 구성 할 수 있습니다. 위의 스레드 중 하나가 응답하지 않는 경우 종료합니다 JVM을 방지 할 수 있다는

Runnable r = new Runnable() { 
    @Override 
    public void run() { 
     try { 
      // code of the shutdown hook: ask running threads to exit gracefully 
      for (Thread t : threadsToShutDown) { 
       t.interrupt(); 
      } 
      for (Thread t : threadsToShutDown) { 
       t.join(); 
      } 
     } 
     catch (InterruptedException e) { 
      // too bad 
     } 
    } 
}; 
Runtime.getRuntime().addShutdownHook(new Thread(r)); 

참고 : 당신이 당신의 종료 훅의 코드는 Runnable를 구현 될 싶다면, 바로 다음 작업을 수행 인터럽트. 타임 아웃을 도입하는 것이 좋습니다.

종료 훅으로 등록한 스레드를 시작하면 안됩니다.

2

닫을 때 Ctrl-C를 누르면 다음을 수행해야합니다. Runtime.getRuntime().addShutdownHook() 스레드가 종료 될 때 종료되도록 스레드가 필요합니다.

번호

docs 당으로 addShutdownHook 단순히 아래 VM이 종료 될 때 (-ting) 실행됩니다 스레드를 등록합니다. 이론적으로 이것은 응용 프로그램 전체 finalizer로 사용됩니다; 당신의 과정이 끝날 때 달릴 무언가는, "위로 정돈하십시오". 그러나 finalizers가 권장되지 않는 이유와 비슷한 몇 가지 문제가 있습니다. 프로세스가 갑자기 종료되면 아무 것도 실행할 수 없으므로 실행되지 않을 수 있습니다. 이들은 라이프 사이클의 섬세한 부분에서 실행되므로 예상대로 객체에 액세스하거나 객체와 상호 작용할 수 없을 수도 있습니다. 그리고 그들은 빨리 달릴 필요가 있습니다. 그렇지 않으면 끝내기 전에 살해 당할 위험에 처합니다.

어쨌든 이것은 과 완전히 다른입니다. VM이 종료되면 필요없이 스레드가 종료됩니다.

게다가, 시작되지 않은 스레드를 종료 후크로 제공해야하므로 종료시에 IllegalThreadState 예외가 발생하지 않는다고 약간 놀랍니다.

Ctrl-C를 통해 종료하고 당신도 멀티 스레드 프로그램을 종료 할 수있는 "일반적인"방법이 아니라고)

Thread.Interrupt (를 통해 그렇게하고자하지 않는 경우.

당신은 (광범위) 두 가지 옵션이 있습니다

  1. 후 그냥 떠날 수, "데몬"로 스레드를 시작

    . 비 데몬 쓰레드가 실행되지 않을 때 프로그램이 종료되므로, main 쓰레드가 종료 될 때 "worker"쓰레드가 여전히 살아 있다고해도 프로그램은 종료됩니다. 이 작업은 물론 종료해야하는 스레드에

  2. 신호 신호가 들어올 때 가장 잘 작동합니다. 부울 플래그를 설정하는 stop() 메서드를 호출하고 해당 스레드가 자신을 종료하도록 허용합니다. 스레드가 run() 메서드가 반환되면 중지됩니다. 일반적으로 스레드는 일종의 루프에있을 때만 계속 실행됩니다. 종료하라는 메시지가 나오면 진행중인 루프를 빠져 나오게하는 것만으로 플래그를 체크하기 전에 일반적으로 현재의 "작업량"을 끝내기 때문에 정상적으로 종료됩니다.

스레드 인터럽트는 예상 한대로 수행되지 않습니다. 내부적으로 부울 플래그를 설정합니다. 파일 시스템/네트워크/데이터베이스 메소드와 같은 많은 블로킹 작업은이 플래그를 주기적으로 검사하고 InterruptedException을 설정합니다 (설정 한 경우). 이것에 의해, 블록 메소드가 일찍 종료 할 수 있습니다 만, 메소드가 "정상적으로 동작하지 않는"경우는 보증되지 않습니다.

예를 들어, Thread.sleep()이 인터럽트에 응답하고이 신호를 종료한다고 생각하기 때문에 작동합니다.그러나 백만 분의 피보나치 수를 계산하는 고유 한 방법을 쓰는 경우, 예를 들어 스레드가 인터럽트를 수행 할 때마다 Thread.currentThread().interrupted()을 명시 적으로 검사하지 않는 한 스레드를 인터럽트하는 것은 아무런 문제가 없습니다.

또한 인터럽트는 거의 모든 곳에서 올 수 있으며 특정 "의미"로 간주하기 어렵습니다. 그들은 실을 죽일 신호입니까? 고객의 지루함 때문에 현재의 방법을 포기할 신호? 새로운 데이터가 도착했기 때문에 신호가 처음부터 시작됩니까? 평범하지 않은 프로그램에서는 완전히 명확하지 않습니다.

부울 플래그를 사용하여 이유를 전달한 다음 플래그를 설정 한 후 을 인터럽트하는 것이 훨씬 더 나은 방법입니다. 인터럽트 된 스레드는 상태를 확인하여 방금 발생한 문제를 확인하고 수행 할 작업을 수행해야합니다. 예를 들어, 당신은 그것을 방해하기 전에 thh.keepRunning = false을 설정 thething.run()

private boolean keepRunning = true; 

public void run() { 
    while(keepRunning) { 
     try {    
      System.out.println("thething class:: Inside while(true) Loop, now sleeping for 2 seconds"); 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
      try { 
       System.out.println("thething class:: has been Inturrupted now sleeping for 2 seconds!!");       
       Thread.sleep(2000); 
      } catch (InterruptedException ex) 
      { 
       System.out.println("thething class:: Second InterruptedException called !!"); 
      } 
     } 
    } 
} 

으로 그리고 QuitIt 코드 (또는 더 나은, 플래그를 설정하는 방법 등 thh.allWorkDone()을 정의하고를) 호출 할 수있다.

강제로 다른 스레드 막을 방법이 없다는 것을

주 - with good reason - 당신은 막을 수있는 스레드 신호 필요하고, 스레드에서 실행중인 무엇이든 그 관찰하고 신호 점 확인합니다.

+0

Thread.currentThread(). interrupt()를 사용하기 위해 수정 된 버전의 프로그램을 구현했습니다.하지만 인터럽트를 발행하더라도 false로 되돌아갑니다. 따라서 신뢰성이 떨어지면 방해가되지 않는 이유는 확실하지 않습니다. – DevilCode

+0

"정상적인 스레드가 실행되지 않고 나머지 스레드가 데몬 스레드 인 경우 인터프리터가 종료됩니다." 그래서 모든 쓰레드가 데몬 쓰레드라면, 당신이 원하지 않더라도 프로그램이 종료됩니까? http://www.roseindia.net/java/thread/daemon-threads.shtml – DevilCode

+0

명확한 문서를 찾을 수 없어 엄청난 실망감을 느끼고 있습니다. 그것이 내려오고있는 것으로 보이는 것은 while (Boolean)을 사용하여 부울 플래그를 변경하여 자신의 스레드를 중지하는 것입니다. Read() 및 다른 IO/Filesystem 호출과 같은 유지 메소드를 중단하는 것을 돕기위한 수단으로 interrupt()를 사용하십시오.하지만이를 신뢰/의존하지 마십시오. Ctrl-C로 무엇을 할 것인가에 관해서는, Runtime.getRuntime(). addShutdownHook()를 사용하여 Ctrl-c 호출시 실행되어야하는 스레드를 등록하십시오. 그런 다음이 스레드를 사용하여 다른 모든 스레드를 정상적으로 종료합니다. 지금까지 수정? – DevilCode

0

엄청난 여백으로 가장 잘 - 명시 적 종료없이 데몬 스레드를 사용하십시오. 다음으로, 애플 리케이션을 재 설계하여 명시 적 종료없이 데몬 스레드를 사용할 수 있습니다. 절대적인 최후의 수단으로, 다른 접근법이 원격으로 가능하지 않을 때 어떤 종류의 명시적인 종료 코드가 여기에 게시되었습니다.