지난 금요일과 주말 바쁜 업무를 잠시 쉬면서 Java Cocurrent를 보면서 Java 5 이후의 Thread.interrupt 및 LockSupport 구현을 검토했습니다.
소개하기 전에 몇 가지 질문을 드리겠습니다.
Thread.interrupt() 메소드와 InterruptedException 사이의 관계는 무엇입니까? InterruptedException 예외가 인터럽트에 의해 트리거됩니까?
Thread.interrupt()는 어떤 상태에서 스레드 작업을 중단합니까? 실행 중인가요, 아니면 차단 중인가요?
일반 스레드 프로그래밍에서는 인터럽트에 주의를 기울여야 합니까? 일반적으로 어떻게 처리하나요? 그것은 무엇을 위해 사용될 수 있습니까?
LockSupport.park()와 unpark(), object.wait()와 inform()의 차이점은 무엇입니까?
LockSupport.park(Object blocker)가 전달한 차단기 개체의 용도는 무엇입니까?
LockSupport가 Thread.interrupt() 이벤트에 응답할 수 있습니까? InterruptedException이 발생하나요?
Thread.interrupt() 처리에 해당하는 콜백 함수가 있습니까? 훅콜 같은 거요?
모든 것에 명확하게 대답할 수 있다면 이미 Thread.interrupt를 완전히 이해했다는 의미이므로 더 이상 읽을 필요가 없습니다.
아직도 불명확하다면, 이 질문들과 함께 정리해보자.
스레드의 인터럽트를 처리하는 여러 가지 방법:
public void Interrupt(): 스레드 인터럽트 이벤트 실행
public boolean isInterrupted() : 현재 스레드가 중단되었는지 확인합니다.
public static boolean Interrupted(): 현재 스레드가 중단되었는지 확인하고 인터럽트 정보를 재설정합니다. ResetAndGet()과 유사함
이해하다:
1. 각 스레드에는 현재 스레드가 중단된 상태인지 여부를 나타내는 인터럽트 상태 플래그가 있습니다.
2. 일반적으로 object.wait(), object.sleep(), object.join()과 같이 우선순위가 낮은 블록 상태에 직면할 때 Thread.interrupt()를 호출할 때 두 가지 처리 방법이 있습니다. 차단 해제를 즉시 트리거하여 차단을 해제하고 InterruptedException을 발생시킵니다.
다른 경우에는 Thread.interrupt()가 상태 플래그만 업데이트합니다. 그런 다음 작업자 스레드는 Thread.isInterrrupted()를 통해 확인하고 InterruptedException 발생, 상태 지우기, 작업 취소 등과 같은 해당 처리를 수행할 수 있습니다.
인터럽트 javadoc에 설명되어 있습니다:
모범 사례
IBM에 아주 좋은 기사가 있습니다. Java 이론 및 실습: InterruptedException 처리(인터럽트 처리에 대한 몇 가지 모범 사례를 언급함)
인터럽트를 삼키지 마십시오(인터럽트를 먹지 마십시오. 일반적으로 두 가지 처리 유형이 있습니다: InterruptedException을 계속 발생시키는 것입니다. 다른 하나는 Thread.interupt() 예외 플래그를 계속 설정하여 더 높은 수준이 그에 따라 처리할 수 있도록 하는 것입니다.
다음과 같이 코드 코드를 복사합니다 .
공개 클래스 TaskRunner는 Runnable을 구현합니다.
개인 BlockingQueue<Task> 대기열;
공개 TaskRunner(BlockingQueue<Task> 대기열) {
this.queue = 대기열;
}
공개 무효 실행() {
노력하다 {
동안 (참) {
작업 task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// 중단된 상태를 복원합니다.
Thread.currentThread().interrupt();
}
}
}
다음과 같이 코드 코드를 복사합니다 .
공개 클래스 TaskRunner는 Runnable을 구현합니다.
개인 BlockingQueue<Task> 대기열;
공개 TaskRunner(BlockingQueue<Task> 대기열) {
this.queue = 대기열;
}
공개 무효 실행() {
노력하다 {
동안 (참) {
작업 task = queue.take(10, TimeUnit.SECONDS);
task.execute();
}
}
catch (InterruptedException e) {
// 중단된 상태를 복원합니다.
Thread.currentThread().interrupt();
}
}
}
Interrupt를 사용하여 취소 가능한 작업 구현(Thread.interrupt()를 사용하여 취소할 수 있는 작업을 설계하고 지원)
다음과 같이 코드 코드를 복사합니다 .
공개 클래스 PrimeProducer는 Thread {를 확장합니다.
개인 최종 BlockingQueue<BigInteger> 대기열;
PrimeProducer(BlockingQueue<BigInteger> 대기열) {
this.queue = 대기열;
}
공개 무효 실행() {
노력하다 {
BigInteger p = BigInteger.ONE;
동안 (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch(InterruptedException이 소비됨) {
/* 스레드 종료를 허용 */
}
}
public void cancel() {interrupt() } //인터럽트를 시작합니다.
}<SPAN style="WHITE-SPACE: 일반"> </SPAN>
다음과 같이 코드 코드를 복사합니다 .
공개 클래스 PrimeProducer는 Thread {를 확장합니다.
개인 최종 BlockingQueue<BigInteger> 대기열;
PrimeProducer(BlockingQueue<BigInteger> 대기열) {
this.queue = 대기열;
}
공개 무효 실행() {
노력하다 {
BigInteger p = BigInteger.ONE;
동안 (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch(InterruptedException이 소비됨) {
/* 스레드 종료를 허용 */
}
}
public void cancel() {interrupt() } //인터럽트를 시작합니다.
}<SPAN style="WHITE-SPACE: 일반"> </SPAN>
인터럽트 처리 이벤트 등록(비정상적 사용)
일반적으로 일반 작업은 취소를 처리하도록 설계되어 있으며 모두 Active Polling을 사용하여 Thread.isInterrupt()를 확인하는데, 이는 비즈니스 자체에 어느 정도 내장되어 있으며 다음까지 기다려야 하는 경우도 있습니다. 체크포인트(다음 체크포인트가 언제인지 누가 알겠습니까? 특히 소켓.read를 수행할 때 HttpClient 시간 초과 문제가 발생했습니다).
InterruptedException을 적극적으로 던지는 구현은 매우 영리한 InterruptibleChannel의 디자인을 기반으로 합니다.
다음과 같이 코드 코드를 복사합니다 .
인터페이스 InterruptAble { // 인터럽트 가능한 인터페이스 정의
공공 무효 인터럽트()는 InterruptedException을 발생시킵니다.
}
추상 클래스 InterruptSupport는 InterruptAble을 구현합니다.
개인 휘발성 부울 중단됨 = false;
개인 인터럽트 인터럽트 = new Interruptible() {
공공 무효 인터럽트() {
중단됨 = 사실;
InterruptSupport.this.interrupt(); // 위치 3
}
};
공개 최종 부울 실행()이 InterruptedException을 발생시킵니다.
노력하다 {
BlockedOn(인터럽터); // 위치 1
if (Thread.currentThread().isInterrupted()) { // 즉시 중단됨
Interruptor.인터럽트();
}
//비즈니스 코드 실행
사업();
} 마지막으로 {
BlockedOn(null); // 위치 2
}
반환이 중단되었습니다.
}
공개 추상 무효 비즈니스() ;
공개 추상 무효 인터럽트();
// -- sun.misc.SharedSecrets --
static void BlockOn(Interruptible intr) { // 패키지 비공개
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
다음과 같이 코드 코드를 복사합니다 .
인터페이스 InterruptAble { // 인터럽트 가능한 인터페이스 정의
공공 무효 인터럽트()는 InterruptedException을 발생시킵니다.
}
추상 클래스 InterruptSupport는 InterruptAble을 구현합니다.
개인 휘발성 부울 중단됨 = false;
개인 인터럽트 인터럽트 = new Interruptible() {
공공 무효 인터럽트() {
중단됨 = 사실;
InterruptSupport.this.interrupt(); // 위치 3
}
};
공개 최종 부울 실행()이 InterruptedException을 발생시킵니다.
노력하다 {
BlockedOn(인터럽터); // 위치 1
if (Thread.currentThread().isInterrupted()) { // 즉시 중단됨
Interruptor.인터럽트();
}
//비즈니스 코드 실행
사업();
} 마지막으로 {
BlockedOn(null); // 위치 2
}
반환이 중단되었습니다.
}
공개 추상 무효 비즈니스() ;
공개 추상 무효 인터럽트();
// -- sun.misc.SharedSecrets --
static void BlockOn(Interruptible intr) { // 패키지 비공개
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
}
}
코드 설명, 몇 가지 요령:
위치 1: 해당 인터럽트 이벤트 처리 후크를 지정된 스레드에 바인딩하려면 sun에서 제공하는 BlockedOn 메서드를 사용합니다.
위치 2: 코드를 실행한 후 후크를 제거합니다. 연결 풀을 사용할 때 다음 스레드 처리 이벤트에 영향을 주지 마십시오.
위치 3: Interruptible 이벤트 후크의 처리 방법을 정의하고 InterruptSupport.this.interrupt() 메서드를 콜백합니다. 하위 클래스는 양말 스트림 닫기 등과 같은 자체 비즈니스 로직을 통합하고 구현할 수 있습니다.
사용:
다음과 같이 코드 코드를 복사합니다 .
InterruptRead 클래스는 InterruptSupport를 확장합니다.
개인 FileInputStream 입력;
@보수
공공 무효 사업() {
File file = new File("/dev/urandom"); // 리눅스 블랙홀을 읽고, 절대 읽지 마세요.
노력하다 {
in = new FileInputStream(파일);
바이트[] 바이트 = 새 바이트[1024];
while (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// 이전 인터럽트 확인 방법
// new InterruptedException("")을 발생시킵니다.
// }
}
} 잡기(예외 e) {
새로운 RuntimeException(e)을 던져라;
}
}
공개 FileInputStream getIn() {
돌아오다;
}
@보수
공공 무효 인터럽트() {
노력하다 {
in.getChannel().close();
} 잡기(IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[])에서 예외가 발생합니다.
최종 InterruptRead 테스트 = new InterruptRead();
스레드 t = 새 스레드() {
@보수
공개 무효 실행() {
긴 시작 = System.currentTimeMillis();
노력하다 {
System.out.println("InterruptRead 시작!");
테스트.실행();
} 잡기(InterruptedException e) {
System.out.println("InterruptRead 종료! 소요 시간 : " + (System.currentTimeMillis() - start));
e.printStackTrace();
}
}
};
t.start();
// 먼저 3초 동안 읽기를 실행하도록 합니다.
Thread.sleep(3000);
//인터럽트 발생
t.인터럽트();
}
다음과 같이 코드 코드를 복사합니다 .
InterruptRead 클래스는 InterruptSupport를 확장합니다.
개인 FileInputStream 입력;
@보수
공공 무효 사업() {
File file = new File("/dev/urandom"); // 리눅스 블랙홀을 읽고, 절대 읽지 마세요.
노력하다 {
in = new FileInputStream(파일);
바이트[] 바이트 = 새 바이트[1024];
while (in.read(bytes, 0, 1024) > 0) {
// Thread.sleep(100);
// if (Thread.interrupted()) {// 이전 인터럽트 확인 방법
// new InterruptedException("")을 발생시킵니다.
// }
}
} 잡기(예외 e) {
새로운 RuntimeException(e)을 던져라;
}
}
공개 FileInputStream getIn() {
돌아오다;
}
@보수
공공 무효 인터럽트() {
노력하다 {
in.getChannel().close();
} 잡기(IOException e) {
e.printStackTrace();
}
}
}
public static void main(String args[])에서 예외가 발생합니다.
최종 InterruptRead 테스트 = new InterruptRead();
스레드 t = 새 스레드() {
@보수
공개 무효 실행() {
긴 시작 = System.currentTimeMillis();
노력하다 {
System.out.println("InterruptRead 시작!");
테스트.실행();
} 잡기(InterruptedException e) {
System.out.println("InterruptRead 종료! 소요 시간 : " + (System.currentTimeMillis() - start));
e.printStackTrace();
}
}
};
t.start();
// 먼저 3초 동안 읽기를 실행하도록 합니다.
Thread.sleep(3000);
//인터럽트 발생
t.인터럽트();
}
jdk 소스 코드 소개:
1. sun에서 제공하는 후크를 사용하면 시스템의 관련 코드인 1125라인을 볼 수 있습니다.
다음과 같이 코드 코드를 복사합니다 .
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
공개 sun.reflect.ConstantPool getConstantPool(클래스 클래스) {
klass.getConstantPool()을 반환합니다.
}
public void setAnnotationType(Class klass, AnnotationType 유형) {
klass.setAnnotationType(type);
}
공개 AnnotationType getAnnotationType(Class klass) {
klass.getAnnotationType()을 반환합니다.
}
공개 <E는 Enum을 확장합니다<E>>
E[] getEnumConstantsShared(Class<E> 클래스) {
klass.getEnumConstantsShared()를 반환합니다.
}
public void BlockedOn(스레드 t, 인터럽트 b) {
t.blockedOn(b);
}
});
다음과 같이 코드 코드를 복사합니다 .
sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
공개 sun.reflect.ConstantPool getConstantPool(클래스 클래스) {
klass.getConstantPool()을 반환합니다.
}
public void setAnnotationType(Class klass, AnnotationType 유형) {
klass.setAnnotationType(type);
}
공개 AnnotationType getAnnotationType(Class klass) {
klass.getAnnotationType()을 반환합니다.
}
공개 <E는 Enum을 확장합니다<E>>
E[] getEnumConstantsShared(Class<E> 클래스) {
klass.getEnumConstantsShared()를 반환합니다.
}
public void BlockOn(스레드 t, 인터럽트 가능 b) {
t.blockedOn(b);
}
});
2. 스레드.인터럽트()
다음과 같이 코드 코드를 복사합니다 .
공공 무효 인터럽트() {
if (이 != Thread.currentThread())
checkAccess();
동기화됨(blockerLock) {
인터럽트 가능 b = 차단기;
if (b != null) {
Interrupt0(); // 인터럽트 플래그를 설정하기 위한 것입니다.
b.interrupt(); //콜백 후크
반품;
}
}
인터럽트0();
}
다음과 같이 코드 코드를 복사합니다 .
공공 무효 인터럽트() {
if (이 != Thread.currentThread())
checkAccess();
동기화됨(blockerLock) {
인터럽트 가능 b = 차단기;
if (b != null) {
Interrupt0(); // 인터럽트 플래그를 설정하기 위한 것입니다.
b.interrupt(); //콜백 후크
반품;
}
}
인터럽트0();
}
Thread.stop, 일시 중단, 재개 및 중단 사용에 대한 자세한 내용은 http://download.oracle.com/javase/6/docs/technotes/guides/concurrency와 같은 Sun 설명서를 참조하세요. /threadPrimitive지원 중단 .html
마지막으로 이전 질문 중 일부에 답해 보겠습니다.
질문 1: Thread.interrupt() 메서드와 InterruptedException 사이의 관계는 무엇입니까? InterruptedException 예외가 인터럽트에 의해 트리거됩니까?
답변: Thread.interrupt()는 Object.wait(), .Object.join() 및 Object.sleep()에서만 적극적으로 InterruptedException을 발생시킵니다. Thread의 플래그 정보만 설정하면 다른 블록에서 흔히 볼 수 있는 일이며, 프로그램 자체적으로 처리해야 합니다.
다음과 같이 코드 코드를 복사합니다 .
if (Thread.interrupted()) // 중단된 상태를 해제합니다!
새로운 InterruptedException()을 던져라;
다음과 같이 코드 코드를 복사합니다 .
if (Thread.interrupted()) // 중단된 상태를 해제합니다!
새로운 InterruptedException()을 던져라;
질문 2: Thread.interrupt()는 어떤 상태에서 스레드 작업을 중단합니까? 실행 중인가요, 아니면 차단 중인가요?
답변: Thread.interrupt 디자인의 목적은 주로 wait() 및 sleep() 상태와 같은 블록 상태의 스레드를 처리하는 것입니다. 단, 프로그램 설계 중에 태스크 취소가 지원될 수 있으며, RUNNING 상태도 지원될 수 있습니다. 예를 들어 Object.join() 및 인터럽트를 지원하는 일부 nio 채널 디자인입니다.
질문 3: 일반 스레드 프로그래밍에서는 인터럽트에 주의를 기울여야 합니까? 일반적으로 어떻게 처리하나요? 그것은 무엇을 위해 사용될 수 있습니까?
답변: 인터럽트 사용: 작업 차단 해제, 작업 취소 지원, 데이터 정리 등
질문 4: LockSupport.park()와 unpark(), object.wait()와 inform()의 차이점은 무엇입니까?
답변:
1. 과목이 다릅니다. LockSuport는 주로 Thread에 대한 차단 처리를 수행하며 차단 대기열의 대상 개체를 지정하고 매번 깨어날 특정 스레드를 지정할 수 있습니다. Object.wait()는 객체를 차원으로 취하여 현재 스레드를 차단하고 단일(임의) 또는 모든 스레드를 깨웁니다.
2. 구현 메커니즘이 다릅니다. LockSuport는 모니터의 객체 객체를 지정할 수 있지만 LockSuport와 object.wait()의 차단 대기열은 교차하지 않습니다. 테스트 예시를 살펴보실 수 있습니다. object.notifyAll()은 LockSupport의 차단 스레드를 깨울 수 없습니다.
질문 5: LockSupport.park(Object blocker)가 전달한 차단기 개체의 용도는 무엇입니까?
답변: 해당 차단기는 Thread의 parkBlocker 속성에 기록됩니다. jstack 명령을 통해 특정 차단 개체를 모니터링하는 것이 매우 편리합니다.
다음과 같이 코드 코드를 복사합니다 .
공공 정적 무효 공원(객체 차단기) {
스레드 t = Thread.currentThread();
setBlocker(t, blocker); //Thread.parkBlocker 속성 값을 설정합니다.
unsafe.park(false, 0L);
setBlocker(t, null); // Thread.parkBlocker 속성 값을 지웁니다.
}
다음과 같이 코드 코드를 복사합니다 .
공공 정적 무효 공원(객체 차단기) {
스레드 t = Thread.currentThread();
setBlocker(t, blocker); //Thread.parkBlocker 속성 값을 설정합니다.
unsafe.park(false, 0L);
setBlocker(t, null); // Thread.parkBlocker 속성 값을 지웁니다.
}
LockSupport에 대한 구체적인 javadoc 설명도 비교적 명확합니다. 아래에서 읽을 수 있습니다.
질문 6: LockSupport가 Thread.interrupt() 이벤트에 응답할 수 있습니까? InterruptedException이 발생하나요?
답변: 인터럽트 이벤트에 응답할 수 있지만 InterruptedException을 발생시키지는 않습니다. LockSupport의 Thread.interrupte 지원과 관련하여 javadoc의 설명도 살펴보세요.
관련 테스트 코드
다음과 같이 코드 코드를 복사합니다 .
패키지 com.agapple.cocurrent;
java.io.파일 가져오기;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
공개 클래스 LockSupportTest {
개인 정적 LockSupportTest 차단기 = 새로운 LockSupportTest();
public static void main(String args[])에서 예외가 발생합니다.
잠금지원테스트();
공원테스트();
인터럽트파크테스트();
InterruptSleepTest();
InterruptWaitTest();
}
/**
* LockSupport.park 객체 이후 Thread.blocker 객체를 획득하고 단일 웨이크업 호출을 시도합니다.
*
* @throwsException
*/
private static void lockSupportTest()에서 예외가 발생합니다. {
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백()에서 예외가 발생합니다.
// 5초 동안 잠자기 시도
System.out.println("차단기");
LockSupport.park(차단기);
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"lockSupportTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(150);
동기화됨(차단기) {
필드 필드 = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
객체 fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* object.wait()를 중단하려고 하면 해당 InterruptedException이 발생합니다.
*
* @throws InterruptedException
*/
개인 정적 무효 InterruptWaitTest()가 InterruptedException을 발생시킵니다.
최종 객체 obj = new Object();
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백()에서 예외가 발생합니다.
// 5초 동안 잠자기 시도
obj.wait();
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"interruptWaitTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
t.interrupt(); // 파크 중 인터럽트에 대한 응답 여부를 확인합니다.
}
/**
* Thread.sleep()을 중단하려고 하면 해당 InterruptedException이 발생합니다.
*
* @throws InterruptedException
*/
개인 정적 무효 InterruptSleepTest()가 InterruptedException을 발생시킵니다.
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백()에서 예외가 발생합니다.
// 5초 동안 잠자기 시도
Thread.sleep(5000);
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"interruptSleepTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
t.interrupt(); // 파크 중 인터럽트에 대한 응답 여부를 확인합니다.
}
/**
* LockSupport.park()를 중단하려고 하면 응답이 있지만 InterruptedException 예외가 발생하지 않습니다.
*
* @throws InterruptedException
*/
개인 정적 무효 InterruptParkTest()가 InterruptedException을 발생시킵니다.
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백() {
//자신의 스레드를 파킹해 보세요.
LockSupport.parkNanos(차단기, TimeUnit.SECONDS.toNanos(5));
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"interruptParkTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
t.interrupt(); // 파크 중 인터럽트에 대한 응답 여부를 확인합니다.
}
/**
* LockSupport.unPark()를 중단하려고 하면 응답이 있을 것입니다.
*
* @throws InterruptedException
*/
private static void parkTest()가 InterruptedException을 발생시킵니다.
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백() {
//자신의 스레드를 파킹해 보세요.
LockSupport.park(차단기);
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"parkTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
LockSupport.unpark(t);
t.인터럽트();
}
공개 정적 스레드 doTest(최종 TestCallBack 호출) {
새로운 Thread() 반환 {
@보수
공개 무효 실행() {
File file = new File("/dev/urandom"); // 리눅스 블랙홀 읽기
노력하다 {
FileInputStream in = new FileInputStream(파일);
바이트[] 바이트 = 새 바이트[1024];
while (in.read(bytes, 0, 1024) > 0) {
if (Thread.interrupted()) {
throw new InterruptedException("");
}
System.out.println(bytes[0]);
Thread.sleep(100);
긴 시작 = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + " 콜백 완료 비용 : "
+ (System.currentTimeMillis() - 시작));
}
} 잡기(예외 e) {
e.printStackTrace();
}
}
};
}
}
인터페이스 TestCallBack {
public void callback()에서 예외가 발생합니다.
공개 문자열 getName();
}
다음과 같이 코드 코드를 복사합니다 .
패키지 com.agapple.cocurrent;
java.io.파일 가져오기;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
공개 클래스 LockSupportTest {
개인 정적 LockSupportTest 차단기 = 새로운 LockSupportTest();
public static void main(String args[])에서 예외가 발생합니다.
잠금지원테스트();
공원테스트();
인터럽트파크테스트();
인터럽트수면 테스트();
InterruptWaitTest();
}
/**
* LockSupport.park 객체 다음에 Thread.blocker 객체를 얻고 단일 깨우기 호출을 시도합니다.
*
* @throwsException
*/
private static void lockSupportTest()에서 예외가 발생합니다. {
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백()에서 예외가 발생합니다.
// 5초 동안 잠자기 시도
System.out.println("차단기");
LockSupport.park(차단기);
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"lockSupportTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(150);
동기화됨(차단기) {
필드 필드 = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(true);
객체 fBlocker = field.get(t);
System.out.println(blocker == fBlocker);
Thread.sleep(100);
System.out.println("notifyAll");
blocker.notifyAll();
}
}
/**
* object.wait()를 중단하려고 하면 해당 InterruptedException이 발생합니다.
*
* @throws InterruptedException
*/
개인 정적 무효 InterruptWaitTest()가 InterruptedException을 발생시킵니다.
최종 객체 obj = new Object();
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백()에서 예외가 발생합니다.
// 5초 동안 잠자기 시도
obj.wait();
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"interruptWaitTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
t.interrupt(); // 파크 중 인터럽트에 대한 응답 여부를 확인합니다.
}
/**
* Thread.sleep()을 중단하려고 하면 해당 InterruptedException이 발생합니다.
*
* @throws InterruptedException
*/
개인 정적 무효 InterruptSleepTest()가 InterruptedException을 발생시킵니다.
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백()에서 예외가 발생합니다.
// 5초 동안 잠자기 시도
Thread.sleep(5000);
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"interruptSleepTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
t.interrupt(); // 파크 중 인터럽트에 대한 응답 여부를 확인합니다.
}
/**
* LockSupport.park()를 중단하려고 하면 응답이 있지만 InterruptedException 예외가 발생하지 않습니다.
*
* @throws InterruptedException
*/
개인 정적 무효 InterruptParkTest()가 InterruptedException을 발생시킵니다.
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백() {
//자신의 스레드를 파킹해 보세요.
LockSupport.parkNanos(차단기, TimeUnit.SECONDS.toNanos(5));
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"interruptParkTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
t.interrupt(); // 파크 중 인터럽트에 대한 응답 여부를 확인합니다.
}
/**
* LockSupport.unPark()를 중단하려고 하면 응답이 있을 것입니다.
*
* @throws InterruptedException
*/
private static void parkTest()가 InterruptedException을 발생시킵니다.
스레드 t = doTest(new TestCallBack() {
@보수
공개 무효 콜백() {
//자신의 스레드를 파킹해 보세요.
LockSupport.park(차단기);
System.out.println("지금 일어나세요!");
}
@보수
공개 문자열 getName() {
"parkTest"를 반환합니다.
}
});
t.start(); // 읽기 스레드를 시작합니다.
Thread.sleep(2000);
LockSupport.unpark(t);
t.인터럽트();
}
공개 정적 스레드 doTest(최종 TestCallBack 호출) {
새로운 Thread() 반환 {
@보수
공개 무효 실행() {
File file = new File("/dev/urandom"); // 리눅스 블랙홀 읽기
노력하다 {
FileInputStream in = new FileInputStream(파일);
바이트[] 바이트 = 새 바이트[1024];
while (in.read(bytes, 0, 1024) > 0) {
if (Thread.interrupted()) {
throw new InterruptedException("");
}
System.out.println(bytes[0]);
Thread.sleep(100);
긴 시작 = System.currentTimeMillis();
call.callback();
System.out.println(call.getName() + " 콜백 완료 비용 : "
+ (System.currentTimeMillis() - 시작));
}
} 잡기(예외 e) {
e.printStackTrace();
}
}
};
}
}
인터페이스 TestCallBack {
public void callback()에서 예외가 발생합니다.
공개 문자열 getName();
}
마지막으로 <BR>글이 점점 길어지는 것을 발견하여 모두가 함께 토론할 수 있도록 포럼에 게시했습니다. 결국 이 글에서는 일부 사용 수준의 내용만 설명했을 뿐 운영에서 Thread를 소개하지 않았습니다. 시스템 또는 Sun 기본 구현에 대해서는 이 분야에 익숙한 다니우멘도 자신의 의견을 표현할 수 있습니다.