머리말
InterruptedException의 경우, 그것을 처리하는 일반적인 방법은 그것을 "삼키"하는 것입니다 - 그것을 잡아서 아무것도하지 않거나 (또는 그것을 기록하지만, 그다지 좋지는 않습니다). 불행히도,이 접근법은이 기간 동안 인터럽트가 발생할 수 있다는 사실을 무시하고 인터럽트로 인해 응용 프로그램이 활동을 취소하거나 제 시간에 닫을 수있는 능력을 상실 할 수 있습니다.
차단 방법
메소드가 InterruptedException을 던지면 특정 점검 예외를 던질 수 있다고 말할뿐만 아니라 다른 것을 알려줍니다. 예를 들어, 차단 방법이라는 것을 알려줍니다.이 방법은 블록을 제거하고 올바르게 응답하면 가능한 한 빨리 반환하려고합니다.
차단 방법은 실행하는 데 시간이 오래 걸리는 일반적인 방법과 다릅니다. 일반적인 방법의 완료는 수행중인 작업과 이용 가능한 충분한 컴퓨팅 리소스 (CPU주기 및 메모리)가 있는지 여부에만 의존합니다. 차단 방법의 완료는 타이머 만료, I/O 완료 또는 다른 스레드의 동작과 같은 일부 외부 이벤트에 따라 다릅니다 (잠금 장치 릴리스, 플래그 설정 또는 작업 대기열에 작업을 배치). 일반적인 방법은 작업이 완료된 후에 끝나고 차단 방법은 외부 이벤트에 의존하기 때문에 예측하기가 더 어렵습니다. 차단 방법은 언제 끝날지 예측하기가 어렵 기 때문에 응답 성에 영향을 줄 수 있습니다.
차단 방법은 기다리고있는 이벤트를 기다릴 수 없기 때문에 종료되지 않을 수 있으므로 차단 방법을 취소 할 수있게하는 것이 매우 유용합니다 (장기 실행되지 않은 비 블로킹 방법을 취소 할 수있는 경우에도 매우 유용합니다). 취소 가능한 작업은 정상 완료 전에 외부에서 종료 될 수있는 작업을 나타냅니다. Thread에서 제공하고 thread.sleep () 및 Object.wait ()에 의해 지원되는 인터럽트 메커니즘은 취소 메커니즘입니다. 하나의 스레드가 다른 스레드가하고있는 일을 중지하도록 요청할 수 있습니다. 메소드가 InterruptedException을 던지면 메소드를 실행하는 스레드가 중단되면 수행중인 작업을 중지하고 미리 돌아 오려고 시도하고 InterruptedException을 던지면 미리 돌아옵니다. 잘 행동하는 차단 라이브러리 방법은 인터럽트에 응답하고 인터럽트 외지를 던져 응답에 영향을 미치지 않고 취소 가능한 활동에 사용할 수 있도록해야합니다.
스레드 인터럽트
각 스레드에는 이와 관련된 부울 속성이 있으며 스레드의 중단 상태를 나타냅니다. 인터럽트 상태는 처음에 거짓입니다. 다른 스레드가 스레드를 호출하여 스레드를 인터럽트하면 두 가지 상황 중 하나가 발생합니다. 해당 스레드가 thread.sleep (), Thread.join () 또는 Object.wait () 와 같은 저수준 인터럽트 블로킹 메소드를 실행하는 경우 차단 해제되어 인터럽트 픽스를 던집니다. 그렇지 않으면 인터럽트 ()는 스레드의 인터럽트 상태를 설정합니다. 중단 된 스레드에서 실행 된 코드 후에는 인터럽트 상태를 폴링하여 수행중인 작업을 중지하도록 요청되는지 확인할 수 있습니다. 인터럽트 상태는 Thread.isinterrupted ()에 의해 읽을 수 있으며 thread.interrupted ()라는 조작으로 읽고 지울 수 있습니다.
중단은 공동 작업 메커니즘입니다. 한 스레드가 다른 스레드를 인터럽트하면 인터럽트 된 스레드가 반드시 수행하는 작업을 멈추지는 않습니다. 대신, 인터럽트는 다른 스레드에 대한 예의 바른 요청으로, 기꺼이 편리 할 때하고있는 일을 중지하기 위해 정중합니다. Thread.sleep ()와 같은 일부 방법은 그러한 요청을 매우 심각하게 받아들이지 만 각 방법이 인터럽트에 반드시 응답 할 필요는 없습니다. 인터럽트 요청의 경우 차단하지 않지만 실행하는 데 시간이 오래 걸리는 방법은 인터럽트 상태를 폴링하고 중단되면 미리 돌아올 수 있습니다. 마음대로 인터럽트 요청을 무시할 수 있지만 그렇게하면 응답에 영향을 미칩니다.
중단의 공동 작업 특성의 한 가지 이점은 취소 가능한 활동을 안전하게 구성 할 수있는 유연성을 더 많이 제공한다는 것입니다. 우리는 활동이 즉시 멈추기를 거의 원하지 않습니다. 업데이트가 진행되는 동안 활동이 취소되면 프로그램 데이터 구조가 일치하지 않을 수 있습니다. 인터럽트를 통해 취소 가능한 활동을 통해 진행중인 작업을 정리하고, 불변량을 복원하고, 다른 활동에 종료되기 전에 취소 될 다른 활동에 알릴 수 있습니다.
InterruptedException을 처리합니다
인터럽트를 던지는 경우 메소드가 차단 방법이라는 것을 의미하는 경우 차단 방법을 호출하는 메소드를 호출하는 메소드도 차단 방법임을 의미하며 인터럽트 꺼짐을 처리하기위한 일종의 전략이 있어야합니다. 가장 쉬운 전략은 일반적으로 Listing 1의 Puttask () 및 getTask () 메소드의 코드에 표시된 것처럼 인터럽트 픽스를 직접 던지는 것입니다. 이렇게하면 메소드가 인터럽트에 응답하고 Drows 조항에 인터럽트 한 예를 추가합니다.
Listing 1. InterruptedException을 잡지 않고 발신자에게 전파
공개 클래스 Taskqueue {개인 정적 최종 int max_tasks = 1000; Private Blockingqueue <asking> queue = new LinkedBlockingqueue <asking> (max_tasks); Public Void Puttask (Task R)는 InterruptedException {queue.put (r); } public task getTask ()가 throws InterruptedException {return queue.take (); }} 때로는 예외가 전파되기 전에 일부 청소 작업이 필요합니다. 이 경우 InterruptedException을 잡고 정리를 수행 한 다음 예외를 던질 수 있습니다. Listing 2는 온라인 게임 서비스의 플레이어와 일치하는 데 사용되는 메커니즘 인이 기술을 보여줍니다. MatchPlayers () 메소드는 두 명의 플레이어가 도착하기를 기다린 다음 새 게임을 시작합니다. 한 플레이어가 도착했지만 다른 플레이어가 도착하지 않았을 때 메소드가 중단되면 해당 플레이어를 대기열에 다시 넣고 인터럽트 링크를 다시 배치하여 플레이어의 게임 요청이 손실되지 않습니다.
Listing 2. InterruptedException을 다시 제외하기 전에 작업 별 정리 작업을 수행하십시오
공개 클래스 PlayerMatcher {Private PlayersOURCE 플레이어; Public PlayerMatcher (Playersource 플레이어) {this.players = 플레이어; } public void matchplayers ()는 중단 된 결과를 던지려고 {try {player playerOne, playertwo; while (true) {playerOne = playertwo = null; // 두 플레이어가 도착하고 새로운 게임을 시작할 때까지 기다립니다. // reaterwo = players.waitforplayer ()를 던질 수 있습니다. // IE StartNewGame (PlayerOne, PlayerTwo)을 던질 수 있습니다. }} catch (InterpruptedException e) {// 플레이어가 한 명이고 중단 된 경우 해당 플레이어를 다시 넣으면 (PlayerOne! = null) 플레이어를 다시 넣으십시오. // 그런 다음 예외 던지기를 전파합니다. }}} 살아있는 삼키는 것을 멈추지 마십시오
예를 들어, 런닝 가능한 작업으로 정의 된 작업이 인터럽트 가능한 메소드를 호출 할 때와 같이 인터럽트 외지를 던지는 것이 적절하지 않습니다. 이 경우 중단 예고는 다시 던질 수는 없지만 아무것도하지 않기를 원하지 않습니다. 차단 방법이 인터럽트를 감지하고 인터럽트 한 외식을 던지면 인터럽트 상태가 지워집니다. InterruptedException이 잡히지 만 다시 던질 수없는 경우 인터럽트의 증거가 발생하여 통화 스택의 상위 레벨 코드가 인터럽트를 알고 응답 할 수 있도록 유지해야합니다. 이 작업은 Interrupt ()를 호출하여 현재 스레드를 "재 해석"하여 목록 3에 표시된대로 수행 할 수 있습니다.
Listing 3. InterruptedException을 캡처 한 후 중단 상태를 재개합니다
공개 클래스 태스크 러너는 런닝 가능한 {private blockingqueue <asking> 대기열을 구현합니다. public taskrunner (blockingqueue <asking> queue) {this.queue = 큐; } public void run () {try {while (true) {task task = queue.take (10, timeUnit.seconds); task.execute (); }} catch (InterpruptedException e) {// 중단 된 상태 스레드를 복원합니다 .CurrentThread (). 인터럽트 (); }}} InterruptedException을 다룰 때해야 할 최악의 일은 그것을 원시를 삼키는 것입니다. 그것을 잡은 다음 그것을 다시 던지거나 스레드의 인터럽트 상태를 다시 알리지 마십시오. 처리 방법을 모른다는 점은 예외적으로 처리하는 가장 표준적인 방법은이를 잡아서 기록하는 것이지만,이 방법은 여전히 원시 인터럽트와 같습니다. 통화 스택의 높은 수준 코드는 여전히 예외에 대한 정보를 얻을 수 없기 때문입니다. (누군가가 로그를 읽을 때 처리하기에는 너무 늦었 기 때문에 InterruptedException을 기록하는 것이 현명하지 않습니다.) Listing 4는 널리 사용되는 패턴을 보여줍니다.이 패턴은 또한 원시 삼키기 중단의 패턴입니다.
목록 4. Raw Swalling Interruption-하지 마십시오
//이 공개 클래스 작업을 수행하지 마십시오 TaskRunner는 실행 가능한 {private blockingqueue <asking> 대기열을 구현합니다. public taskrunner (blockingqueue <asking> queue) {this.queue = 큐; } public void run () {try {while (true) {task task = queue.take (10, timeUnit.seconds); task.execute (); }} catch (InterruptedException Swallowed) { / * 이것을하지 마십시오 - 대신 중단 된 상태를 복원 * /}}}} 인터럽트 요청을 처리 할 것인지 여부에 관계없이 인터럽트 외지를 다시 던질 수없는 경우, 하나의 인터럽트 요청에 여러 "수신기"가있을 수 있으므로 현재 스레드를 다시 중단해야합니다. 표준 스레드 풀 (ThreadPoolexecutor) 작업자 스레드 구현은 중단을 담당하므로 실행중인 스레드 풀에서 작업을 방해하면 이중 효과가 발생할 수 있습니다. 하나는 작업을 취소하고 다른 하나는 실행 스레드에 스레드 풀이 닫히는 것을 알리는 것입니다. 작업이 요청을 삼키면 작업자 스레드는 요청 된 인터럽트가 있음을 알지 못하여 응용 프로그램 또는 서비스의 종료를 지연시킵니다.
취소 된 작업을 구현합니다
언어 사양의 인터럽트에 대한 특정 의미는 없지만 더 큰 프로그램에서는 취소를 제외한 인터럽트 의미를 유지하기가 어렵습니다. 활동이 무엇인지에 따라 사용자는 GUI 또는 JMX 또는 웹 서비스와 같은 네트워크 메커니즘을 통해 취소를 요청할 수 있습니다. 프로그램 로직을 취소하도록 요청할 수도 있습니다. 예를 들어, 웹 크롤러는 디스크가 가득 찼음을 감지하면 자동으로 종료됩니다. 그렇지 않으면 병렬 알고리즘은 여러 스레드를 시작하여 솔루션 공간의 다른 영역을 검색하고 스레드 중 하나가 솔루션을 찾으면 스레드를 취소합니다.
작업을 취소 할 수 있다고해서 인터럽트 요청이 즉시 응답해야한다는 의미는 아닙니다. 루프에서 코드를 실행하는 작업의 경우 일반적으로 각 루프 반복에 대해 한 번만 인터럽트를 확인하면됩니다. 루프가 실행되는 기간에 따라 스레드가 중단되었음을 알리는 데 약간의 시간이 걸릴 수 있습니다 (스레드를 호출하여 인터럽트 상태를 폴링하거나 차단 방법을 호출). 작업이 반응이 필요한 경우 인터럽트 상태를 더 자주 투표 할 수 있습니다. 차단 방법은 일반적으로 입구에서 인터럽트 상태를 즉시 폴링하며 응답 성을 향상시키기 위해 설정되면 중단 예고가 발생합니다.
살아있는 삼키기를 멈출 수있는 유일한 시간은 스레드가 종료 될 예정이라는 것을 알고 있다는 것입니다. 이 시나리오는 중단 가능한 메소드를 호출하는 클래스가 실행할 수 없거나 일반 라이브러리 코드가 아닌 스레드의 일부일 때만 발생합니다. 목록 5에 표시된 것처럼 Listing 5는 중단 될 때까지 소수를 나열하는 스레드를 생성하며, 이는 중단 될 때 종료 할 수 있습니다. 두 곳에서 Primes 검사 검색을 검색하는 데 사용되는 루프는 다음과 같습니다. 하나는 While 루프 헤드에서 islerrupted () 메소드를 투표하는 것입니다. 다른 하나는 차단 방법 Blockingqueue.put ()을 호출하는 것입니다.
Listing 5. 스레드가 종료하려고한다는 것을 알고 있다면 인터럽트를 삼킬 수 있습니다.
Public Class PrimeProducer Extends Thread {Private Final Blockingqueue <BigInteger> 대기열; PRYPRODUCER (Blockingqueue <Biginteger> 대기열) {this.queue = 대기열; } public void run () {try {biginteger p = biginteger.one; while (! thread.currentThread (). islerrupted ()) queue.put (p = p.nextProbablePrime ()); } catch (InterpruptedException 소비) { / * 실행을 허용 * /}} public void cancel () {인터럽트 (); }} 무정식 차단 방법
모든 차단 방법이 중단 된 예고를 던지는 것은 아닙니다. 입력 및 출력 스트림 클래스는 I/O가 완료되기를 기다리는 블록이지만, 중단 된 예고는 방해하지 않으며 중단되면 미리 돌아 오지 않습니다. 그러나 소켓 I/O의 경우 스레드가 소켓을 닫으면 해당 소켓의 차단 I/O 작동이 조기에 끝나고 Pocketexception이 발생됩니다. java.nio의 비 블로킹 I/O 클래스는 인터럽트 가능한 I/O를 지원하지 않지만 채널을 닫거나 선택기의 웨이크 업을 요청하여 차단 해제 될 수도 있습니다. 마찬가지로 내부 잠금 장치 (동기화 된 블록 입력)를 획득하려는 시도는 중단 될 수 없지만 ReintrantLock은 중단 가능한 획득 모드를 지원합니다.
이행 할 수없는 작업
일부 작업은 중단을 거부하여 비비불화되지 않습니다. 그러나, 암시 불가능한 작업조차도 콜 스택의 고급 코드가 암시 할 수없는 작업이 끝난 후 인터럽트를 처리 해야하는 경우 인터럽트 상태를 보존하려고 시도해야합니다. Listing 6은 중단 여부에 관계없이 사용 가능한 항목이 큐에 나타날 때까지 차단 대기열을 기다리는 메소드를 보여줍니다. 편의를 위해, 인터럽트 요청의 발신자를 박탈하지 않도록 마지막으로 블록에서 종료 후 인터럽트 상태를 재개합니다. (인터럽트 상태를 일찍 재개 할 수는 없습니다. 이로 인해 무한 루프가 발생할 수 있기 때문에 - blockingqueue.take.take.take는 즉시 입구의 인터럽트 상태를 폴링하고 인터럽트 상태 세트가 발견되면 인터럽트 지출이 발생합니다.)
목록 6. 반환하기 전에 중단 된 상태를 복원하는 재능이없는 작업
공개 작업 getNextTask (Blockingqueue <aveSt> 대기열) {boolean Interrupted = false; try {while (true) {try {return queue.take (); } catch (InterruptedException e) {Interrupted = true; // 가속화되고 재 시도}}} 마지막으로 {if (Interrupted) thread.currentThread (). 인터럽트 (); }} 요약
Java 플랫폼에서 제공하는 협업 인터럽트 메커니즘을 사용하여 유연한 취소 전략을 구성 할 수 있습니다. 활동은 자신의 재량에 따라 취소 할 수 있는지 또는 암시 불가능한 지, 인터럽트에 대응하는 방법을 결정할 수 있으며, 즉각적인 수익이 응용 프로그램 무결성을 손상시킬 경우 인터럽트를 연기 할 수도 있습니다. 코드에서 인터럽트를 완전히 무시하고 싶더라도 인터럽트 상태가 다시 제기되지 않고 인터럽트 상태가 복원되어야하므로 코드 호출이 인터럽트가 발생하는 내용을 알지 못하게해야합니다. 위의 내용은 Java의 이론과 중단 예외를 처리하는 실천의 전체 내용입니다. 이 기사가 도움이되기를 바랍니다. 궁금한 점이 있으면 토론을위한 메시지를 남겨주세요.