JAVA 스 레 드 를 자세히 알 아 보 세 요.-스 레 드 상 태 는 어떤 게 있 나 요?그것 은 어떻게 일 합 니까?
하나의 프로 세 스 에는 여러 개의 스 레 드 가 포함 되 어 있 습 니 다.다 중 스 레 드 는 메모리 공간 과 시스템 자원 을 공유 할 수 있 기 때문에 스 레 드 간 의 전환 은 자원 을 더욱 절약 하고 경 량 화 되 기 때문에 경량급 프로 세 스 라 고 불 립 니 다.
스 레 드 의 상 태 는 JDK 1.5 이후 Thread 의 소스 코드 에 매 거 진 방식 으로 정의 되 었 습 니 다.총 6 개의 상 태 를 포함 합 니 다.
public enum State {
/**
* , ,
*/
NEW,
/**
* , , CPU
*/
RUNNABLE,
/**
* ,
* , synchronized
* synchronized
*/
BLOCKED,
/**
* , 。
* , Object.wait()
* Object.notify() Object.notifyAll()
*/
WAITING,
/**
* , (WAITING) , ,
* Object.wait(long timeout)
* Thread.join(long timeout)
*/
TIMED_WAITING,
/**
* ,
*/
}
스 레 드 의 작업 모드 는 먼저 스 레 드 를 만 들 고 스 레 드 가 실행 해 야 할 업무 방법 을 지정 한 다음 에 스 레 드 의 start()방법 을 호출 하 는 것 입 니 다.이때 스 레 드 는 NEW(새로 만 들 기)상태 에서 RUNNABLE(준비)상태 로 바 뀌 었 습 니 다.그 다음 에 스 레 드 는 실행 할 방법 중 synchronized 동기 코드 블록 이 있 는 지 판단 합 니 다.다른 스 레 드 도 이 자 물 쇠 를 사용 하면 스 레 드 는 BLOCKED(대기 차단)상태 로 변 합 니 다.다른 스 레 드 가 이 자 물 쇠 를 사용 한 후에 스 레 드 는 남 은 방법 을 계속 실행 합 니 다.
Object.wait()또는 Thread.join()방법 을 만 났 을 때 스 레 드 는 WAITING(대기 상태)상태 로 변 합 니 다.
시간 초과 대기 방법 이 있 으 면 스 레 드 는 TIMED 에 들 어 갑 니 다.WAITING(타이머 대기)상태;
다른 스 레 드 가 notify()또는 notify All()방법 을 실행 한 후에 스 레 드 는 나머지 업무 방법 을 계속 실행 하 는 것 을 깨 워 서 방법 이 실 행 될 때 까지 전체 스 레 드 의 절 차 는 실 행 됩 니 다.실행 절 차 는 다음 그림 과 같 습 니 다.
[BLOCKED 와 WAITING 의 차이 점]
BLOCKED 와 WAITING 은 기다 린 다 는 의미 가 있 지만 본질 적 인 차이 가 있다.
우선 이들 상태 에서 형 성 된 호출 방법 은 다르다.
그 다음 에 BLOCKED 는 현재 스 레 드 가 활성 상태 에 있 고 다른 스 레 드 가 특정한 잠 금 자원 을 사용 하 기 를 기다 리 는 것 을 막 는 것 으로 이해 할 수 있 습 니 다.
한편,WAITING 은 Object.wait()또는 Thread.join()또는 LockSupport.park()를 자체 호출 하여 대기 상태 에 들 어 갔 기 때문에 다른 스 레 드 가 특정한 동작 을 수행 할 때 까지 기 다 려 야 계속 깨 어 날 수 있 습 니 다.
예 를 들 어 스 레 드 가 Object.wait()를 호출 하여 WAITING 상태 에 들 어간 후에 다른 스 레 드 가 Object.notify()나 Object.notify All()을 실행 할 때 까지 기 다 려 야 깨 어 날 수 있 습 니 다.
[start()와 run()의 차이 점]
먼저 Thread 소스 코드 를 보면 start()방법 은 Thread 자체 의 방법 에 속 하고 synchronized 를 사용 하여 스 레 드 안전 을 확보 합 니 다.소스 코드 는 다음 과 같 습 니 다.
public synchronized void start() {
// , NEW
if (threadStatus != 0)
throw new IllegalThreadStateException();
// ,
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
// , start0 ,
}
}
}
run()방법 은 Runnable 의 추상 적 인 방법 입 니 다.호출 클래스 에서 이 방법 을 다시 써 야 합 니 다.다시 쓰 는 run()방법 은 바로 이 스 레 드 가 실행 할 업무 방법 입 니 다.소스 코드 는 다음 과 같 습 니 다.
public class Thread implements Runnable {
// ......
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
실행 효과 에 있어 start()방법 은 다 중 스 레 드 를 열 어 NEW 상태 에서 RUNABLE 상태 로 전환 시 킬 수 있 으 며,run()방법 은 일반적인 방법 일 뿐이다.그 다음으로 호출 가능 한 횟수 가 다 르 기 때문에 start()방법 은 여러 번 호출 될 수 없습니다.그렇지 않 으 면 자바.lang.IllegalState Exception 을 던 집 니 다.run()방법 은 일반적인 방법 일 뿐 이기 때문에 여러 번 호출 할 수 있다.
[스 레 드 우선 순위]
Thread 소스 코드 에서 스 레 드 우선 순위 와 관련 된 속성 은 3 개 입 니 다:
//
public final static int MIN_PRIORITY = 1;
//
public final static int NORM_PRIORITY = 5;
//
public final static int MAX_PRIORITY = 10
스 레 드 의 우선 순 위 는 스 레 드 가 CPU 시간 편 을 선점 할 확률 로 이해 할 수 있 습 니 다.우선 순위 가 높 을 수록 스 레 드 가 우선 실 행 될 확률 이 높 지만 우선 순위 가 높 은 스 레 드 가 반드시 먼저 실 행 될 것 이 라 고 보장 할 수 없습니다.프로그램 에서 우 리 는 Thread.setPriority()를 통 해 우선 순 위 를 설정 할 수 있 습 니 다.setPriority()소스 코드 는 다음 과 같 습 니 다.
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
//
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
// ,
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
[라인 의 상용 방법]스 레 드 의 상용 방법 은 다음 과 같은 몇 가지 가 있다.
join()
한 스 레 드 에서 other.join()을 호출 합 니 다.이 때 현재 스 레 드 는 other 스 레 드 가 실행 되 거나 시간 이 지나 면 현재 스 레 드 를 계속 실행 합 니 다.join()소스 코드 는 다음 과 같 습 니 다.
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
// 0
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
// 0 ,
if (millis == 0) {
// ( ) ,
while (isAlive()) {
wait(0);
}
} else {
//
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
원본 코드 에서 알 수 있 듯 이 join()방법의 밑바닥 은 wait()방법 을 통 해 이 루어 진다.예 를 들 어 join()을 사용 하지 않 았 을 때 코드 는 다음 과 같 습 니 다.
public class ThreadExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 1; i < 6; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" :" + i + " 。");
}
});
thread.start(); //
//
for (int i = 1; i < 4; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" :" + i + " 。");
}
}
}
프로그램 실행 결 과 는:주 스 레 드 수면 복사:1 초.
서브 스 레 드 수면:1 초.
주 스 레 드 수면:2 초.
서브 스 레 드 수면:2 초.
주 스 레 드 수면:3 초.
서브 스 레 드 수면:3 초.
서브 스 레 드 수면:4 초.
서브 스 레 드 수면:5 초.
결 과 를 보면 join()을 사용 하지 않 을 때 메 인 스 레 드 가 교체 되 어 실 행 됩 니 다.
그리고 우 리 는 join()방법 을 코드 에 넣 었 습 니 다.코드 는 다음 과 같 습 니 다.
public class ThreadExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 1; i < 6; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" :" + i + " 。");
}
});
thread.start(); //
thread.join(2000); // 2
//
for (int i = 1; i < 4; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" :" + i + " 。");
}
}
}
프로그램 실행 결 과 는:하위 스 레 드 수면 복사:1 초.
서브 스 레 드 수면:2 초.
주 스 레 드 수면:1 초.
// thread.join(2000); 2 초 를 기다 린 후 메 인 스 레 드 와 하위 스 레 드 를 교체 하여 실행 합 니 다.
서브 스 레 드 수면:3 초.
주 스 레 드 수면:2 초.
서브 스 레 드 수면:4 초.
서브 스 레 드 수면:5 초.
주 스 레 드 수면:3 초.
실행 결 과 를 통 해 알 수 있 듯 이 join()방법 을 추가 한 후에 메 인 스 레 드 는 2 초 후에 야 계속 실 행 됩 니 다.
yield()
Thread 의 소스 코드 를 보면 yield()를 로 컬 방법 으로 알 수 있 습 니 다.즉,yield()는 C 또는 C++로 이 루어 진 것 입 니 다.소스 코드 는 다음 과 같 습 니 다.
public static native void yield();
yield()방법 은 현재 스 레 드 스케줄 러 에 CPU 사용권 을 양도 하 겠 다 는 암 시 를 표시 하지만 스 레 드 스케줄 러 는 이 암 시 를 무시 할 수 있 습 니 다.예 를 들 어 우 리 는 이 단락 에 yield()방법 을 포함 하 는 코드 를 실행 합 니 다.다음 과 같 습 니 다.
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(" :" +
Thread.currentThread().getName() + " I:" + i);
if (i == 5) {
Thread.yield();
}
}
}
};
Thread t1 = new Thread(runnable, "T1");
Thread t2 = new Thread(runnable, "T2");
t1.start();
t2.start();
}
이 코드 를 여러 번 실행 한 후에 매번 실 행 된 결과 가 다르다 는 것 을 알 게 될 것 입 니 다.이것 은 yield()의 실행 이 매우 불안정 하기 때 문 입 니 다.스 레 드 스케줄 러 가 반드시 yield()가 CPU 사용권 을 양도 하 는 건 의 를 받 아들 이지 않 아서 이런 결 과 를 초래 했 습 니 다.지금까지 JAVA 스 레 드 를 자세히 알 아 봤 습 니 다.-스 레 드 상 태 는 어떤 게 있 나 요?그것 은 어떻게 일 합 니까?자바 스 레 드 에 관 한 더 많은 자 료 는 우리 의 다른 관련 글 을 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JAVA 객체 작성 및 제거 방법정적 공장 방법 정적 공장 방법의 장점 를 반환할 수 있습니다. 정적 공장 방법의 단점 류 공유되거나 보호된 구조기를 포함하지 않으면 이불류화할 수 없음 여러 개의 구조기 파라미터를 만났을 때 구축기를 고려해야 한다...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.