JAVA 스 레 드 상태 에 존재 할 수 있 는 잘못된 부분 에 대해 말씀 드 리 겠 습 니 다.

BLOCKED 와 WAITING 의 차이 점.
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 상태 로 들 어 갈 수 있 습 니 다.
  • Object.wait()
  • Thread.join()
  • LockSupport.park()
  • WAITING 상태의 스 레 드 는 다른 스 레 드 가 어떤 작업 을 수행 하 기 를 기다 리 고 있 습 니 다.예 를 들 어 대상 에서 Object.wait()를 호출 하 는 스 레 드 는 다른 스 레 드 가 대상 에서 Object.notify()나 Object.notify All()을 호출 하 기 를 기다 리 고 있 습 니 다.Thread.join()을 위 한 스 레 드 가 지정 한 스 레 드 가 멈 추 기 를 기다 리 고 있 습 니 다.
    다음 코드 에서 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 스 레 드 상태 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기