JAVA 스 레 드 상태 에 존재 할 수 있 는 잘못된 부분 에 대해 말씀 드 리 겠 습 니 다.
BLOCKED 와 WAITING 두 가지 상 태 는 결과 적 으로 볼 때 모두 스 레 드 가 일시 정지 되 어 CPU 자원 을 차지 하지 않 지만 차이 가 있 습 니 다.
BLOCKED
Monitor 잠 금 을 기다 리 는 차단 스 레 드 상태 입 니 다.차단 상태 에 있 는 스 레 드 는 Monitor 잠 금 이 synchronized 에 들 어 오 기 를 기다 리 고 있 습 니 다. Block 또는 Method,또는 Object.wait 를 호출 한 후 동기 블록/방법 에 다시 들 어 갑 니 다.쉽게 말 하면 스 레 드 가 synchronized 형식의 잠 금 을 기다 리 는 상태 입 니 다.
다음 코드 에서 t1 은 t0 의 잠 금 해제(synchronized 코드 블록 실행 완료)를 기다 리 고 있 습 니 다.이때 t1 의 상 태 는 BLOCKED 입 니 다.
Object lock = new Object();
Thread t0 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println("t0 acquire lock success");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t0.start();
Thread.sleep(100);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println("t1 acquire lock success");
}
}
});
t1.start();
Thread.sleep(100);
System.out.println("t0 state: "+t0.getState());
System.out.println("t1 state: "+t1.getState());
System.out.println("done.");
//output
t0 acquire lock success
t0 state: TIMED_WAITING
t1 state: BLOCKED
done.
t1 acquire lock success
WAITING대기 중인 스 레 드 상태 입 니 다.다음 몇 가지 방법 을 호출 하면 스 레 드 가 WAITING 상태 로 들 어 갈 수 있 습 니 다.
다음 코드 에서 t0 은 synchronized 를 통 해 lock 대상 의 자 물 쇠 를 가 져 온 후에 wait 작업 을 하여 t0 이 WAITING 상태 에 들 어 갑 니 다.
Object lock = new Object();
Thread t0 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println("t0 acquire lock success");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t0.start();
Thread.sleep(100);
System.out.println("t0 state: "+t0.getState());
System.out.println("done.");
//output
t0 acquire lock success
t0 state: WAITING
done.
구별JAVA 에 서 는 synchronized Block/Method 의 자물쇠 뿐만 아니 라 JUC 의 잠 금 실현 도 제공 하 며,jc.lock 의 잠 금 기능 이 더욱 강하 다.예 를 들 어 중단 을 지지 하고 재 입/비 재 입,공평/비공 평등 을 지지 합 니 다.그런데 Juc 의 자물쇠 와 synchronized 의 실현 은 다 릅 니 다.
예 를 들 어 아래 코드 는 똑 같이 자 물 쇠 를 기다 리 는 것 이지 만 synchronized 가 자 물 쇠 를 기다 리 는 상태 와 는 다 릅 니 다.
ReentrantLock reentrantLock = new ReentrantLock();
Thread t0 = new Thread(new Runnable() {
@Override
public void run() {
reentrantLock.lock();
System.out.println("t0 acquire lock success");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t0.start();
Thread.sleep(100);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
reentrantLock.lock();
System.out.println("t1 acquire lock success");
}
});
t1.start();
Thread.sleep(100);
System.out.println("t0 state: "+t0.getState());
System.out.println("t1 state: "+t1.getState());
System.out.println("done.");
//output
t0 acquire lock success
t0 state: TIMED_WAITING
t1 state: WAITING
done.
마찬가지 로 잠 금 을 추가 하고 JUC 의 잠 금 실현 에서 스 레 드 상태 가 다 르 기 때문에 스 레 드 상 태 를 관찰 할 때 BLOCKED 의 상태 만 이 잠 금 을 기다 리 는 것 이 아니 라 WAITING/TIMEWAITING 의 상 태 는 잠 금 을 기다 리 는 상태 일 수 있 습 니 다.그러나 JUC 의 잠 금 이 실현 되 고 스 레 드 를 일시 정지/기다 리 게 하 는 핵심 방법 은 LockSupport.park 입 니 다.jstack 는 PARKING 형식의 WAITING 에 표시 되 어 있 기 때문에 스 레 드 stack 에서 한눈 에 알 수 있 습 니 다.
//대기 유형 표시
"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9308110000 nid=0x5c03 waiting on condition [0x0000700007fc3000]
java.lang.Thread.State:WAITING(parking)//여 기 는 WAITING 이지 만 parking 형식 이 라 고 표시 되 어 있 습 니 다.
at sun.misc.Unsafe.park(Native Method)
그리고 synchronized 형식의 잠 금 은 jstack 에서 의 출력 과 차이 가 있 습 니 다.
//대기 형식 이 모니터 로 표시 되 어 있 습 니 다.
"Thread-1" #12 prio=5 os_prio=31 tid=0x00007f833d919800 nid=0x5a03 waiting for monitor entry [0x00007000035af000]
java.lang.Thread.State:BLOCKED(on object monitor)//여 기 는 BLOCKED 상태 이 며,monitor 의 귀속 도 표시 합 니 다.
따라서 스 레 드 상 태 를 관찰 할 때 Object.wait()와 같은 WAITING 과 jc 의 잠 금 으로 인 한 WAITING 의 차 이 를 주의해 야 합 니 다.
RUNNABLE 이 진짜 RUNNABLE 인가요?
다음은 jstack 출력 의 예 입 니 다.이 스 레 드 는 현재 socketRead 0 방법(Native)을 실행 하고 있 으 며 RUNNABLE 상태 입 니 다.
"RMI TCP Connection(2)-192.xxx.xx.xx" daemon prio=6 tid=0x000000000a3e8800 nid=0x158e50 runnable [0x000000000adbe000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
- locked (0x00000007ad784010) (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
그러나 사실 이곳 의 RUNABLE 은 JAVA 차원 의 스 레 드 상태 일 뿐 운영 체제 나 프로 세 스 측면 에서 볼 때 이 스 레 드 는 WAITING 의 상태 입 니 다.SocketInputStream 은 BIO 의 실현 입 니 다.데 이 터 를 받 지 못 했 거나 읽 을 데이터 가 준비 되 지 않 았 을 때 차단 이 발생 합 니 다.그러나 이 차단 은 JAVA 스 레 드 상태 에서 RUNNABLE 상태 입 니 다.그러나 사용자 상태의 CPU 시간 대 를 차지 하지 않 습 니 다.커 널 은 데 이 터 를 받 은 후에 이 차단 을 끝 냅 니 다.
레 퍼 런 스
https://blog.fastthread.io/2018/09/02/threads-stuck-in-java-net-socketinputstream-socketread0/
JAVA 스 레 드 상태 에 존재 할 수 있 는 잘못된 부분 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 JAVA 스 레 드 상태 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JAVA 객체 작성 및 제거 방법정적 공장 방법 정적 공장 방법의 장점 를 반환할 수 있습니다. 정적 공장 방법의 단점 류 공유되거나 보호된 구조기를 포함하지 않으면 이불류화할 수 없음 여러 개의 구조기 파라미터를 만났을 때 구축기를 고려해야 한다...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.