You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
getPriority(): 스레드의 우선순위를 반환하는 메서드이다. 우선순위는 1 (가장 낮음)에서 10 (가장 높음)까지의
값으로 설정할 수 있으며, 기본값은 5이다. setPriority() 메서드를 사용해서 우선순위를 변경할 수 있다.
우선순위는 스레드 스케줄러가 어떤 스레드를 우선 실행할지 결정하는 데 사용된다. 하지만 실제 실행 순서는
JVM 구현과 운영체제에 따라 달라질 수 있다.
스레드 그룹
getThreadGroup(): 스레드가 속한 스레드 그룹을 반환하는 메서드이다. 스레드 그룹은 스레드를 그룹화하여 관리할 수 있는 기능을 제공한다. 기본적으로 모든 스레드는 부모 스레드와 동일한 스레드 그룹에 속하게 된다. 스레드 그룹은 여러 스레드를 하나의 그룹으로 묶어서 특정 작업(예: 일괄 종료, 우선순위 설정 등)을 수행할 수 있다.
부모스레드(Parent Thread)*: 새로운 스레드를 생성하는 스레드를 의미한다. 스레드는 기본적으로 다른 스레드에 의해 생성된다. 이러한 생성 관계에서 새로 생성된 스레드는 생성한 스레드를 부모로 간주한다. 예를 들어
myThread 는 main 스레드에 의해 생성되었으므로 main 스레드가 부모 스레드이다. main 스레드는 기본으로 제공되는 main 스레드 그룹에 소속되어 있다. 따라서 myThread 도 부모 스레드인
main 스레드의 그룹인 main 스레드 그룹에 소속된다.
참고: 스레드 그룹 기능은 직접적으로 잘 사용하지는 않기 때문에, 이런 것이 있구나 정도만 알고 넘어가자
. 반환되는 값은 Thread.State 열거형에 정의된 상 수 중 하나이다. 주요 상태는 다음과 같다.
NEW: 스레드가 아직 시작되지 않은 상태이다.
RUNNABLE: 스레드가 실행 중이거나 실행될 준비가 된 상태이다.
BLOCKED: 스레드가 동기화 락을 기다리는 상태이다.
WAITING: 스레드가 다른 스레드의 특정 작업이 완료되기를 기다리는 상태이다.
TIMED_WAITING: 일정 시간 동안 기다리는 상태이다.
TERMINATED: 스레드가 실행을 마친 상태이다.
2️⃣ 스레드의생명주기 - 설명
스레드의 상태
New (새로운상태) 스레드가 생성되었으나 아직 시작되지 않은 상태.
Runnable (실행가능상태): 스레드가 실행 중이거나 실행될 준비가 된 상태.
일시중지상태들 (Suspended States)
Blocked (차단상태): 스레드가 동기화 락을 기다리는 상태.
Waiting (대기상태): 스레드가 무기한으로 다른 스레드의 작업을 기다리는 상태.
Timed Waiting (시간제한대기상태): 스레드가 일정 시간 동안 다른 스레드의 작업을 기다리는 상태.
Terminated (종료상태): 스레드의 실행이 완료된 상태.
참고: 자바에서 스레드의 일시중지상태들(Suspended States)이라는 상태는 없다. 스레드가 기다리는 상태들을 묶어서 쉽게 설명하기 위해 사용한 용어이다.
자바 스레드(Thread)의 생명 주기는 여러 상태(state)로 나뉘어지며, 각 상태는 스레드가 실행되고 종료되기까지의 과정을 나타낸다.
1️⃣ New (새로운상태)
스레드가 생성되고 아직 시작되지 않은 상태이다.
이 상태에서는 Thread 객체가 생성되지만, start() 메서드가 호출되지 않은 상태이다.
예: Thread thread = new Thread(runnable);
2️⃣ Runnable (실행가능상태)
스레드가 실행될 준비가 된 상태이다. 이 상태에서 스레드는 실제로 CPU에서 실행될 수 있다.
start() 메서드가 호출되면 스레드는 이 상태로 들어간다.
예: thread.start();
이 상태는 스레드가 실행될 준비가 되어 있음을 나타내며, 실제로 CPU에서 실행될 수 있는 상태이다. 그러나 Runnable 상태에 있는 모든 스레드가 동시에 실행되는 것은 아니다. 운영체제의 스케줄러가 각 스레드에 CPU 시간을 할당하여 실행하기 때문에, Runnable 상태에 있는 스레드는 스케줄러의 실행 대기열에 포함되어 있다가 차례로 CPU에서 실행된다.
참고로 운영체제 스케줄러의 실행 대기열에 있든, CPU에서 실제 실행되고 있든 모두 RUNNABLE 상태이다. 자바에서 둘을 구분해서 확인할 수는 없다.
보통 실행 상태라고 부른다.
3️⃣ Blocked (차단상태)
스레드가 다른 스레드에 의해 동기화 락을 얻기 위해 기다리는 상태이다.
예를 들어, synchronized 블록에 진입하기 위해 락을 얻어야 하는 경우 이 상태에 들어간다.
예: synchronized (lock) { ... }코드 블록에 진입하려고 할 때, 다른 스레드가 이미 lock 의 락을 가지고 있는 경우.
지금은 이런 상태가 있다 정도만 알아두자. 이 부분은 뒤에서 자세히 다룬다.
4️⃣ Waiting (대기상태)
스레드가 다른 스레드의 특정 작업이 완료되기를 무기한 기다리는 상태이다.
wait(), join() 메서드가 호출될 때 이 상태가 된다.
스레드는 다른 스레드가 notify() 또는 notifyAll() 메서드를 호출하거나, join() 이 완료될 때 까지 기다린다.
예: object.wait();
지금은 이런 상태가 있다 정도만 알아두자. 이 부분은 뒤에서 자세히 다룬다.
5️⃣ Timed Waiting (시간제한대기상태)
스레드가 특정 시간 동안 다른 스레드의 작업이 완료되기를 기다리는 상태이다.
sleep(long millis) , wait(long timeout) , join(long millis) 메서드가 호출될 때 이 상태가 된다.
주어진 시간이 경과하거나 다른 스레드가 해당 스레드를 깨우면 이 상태에서 벗어난다.
예: Thread.sleep(1000);
지금은 이런 상태가 있다 정도만 알아두자. 이 부분은 뒤에서 자세히 다룬다.
6️⃣ Terminated (종료상태)
스레드의 실행이 완료된 상태이다.
스레드가 정상적으로 종료되거나, 예외가 발생하여 종료된 경우 이 상태로 들어간다.
스레드는 한 번 종료되면 다시 시작할 수 없다.
✅ 자바스레드의상태전이과정
New → Runnable: start() 메서드를 호출하면 스레드가 Runnable 상태로 전이된다.
Runnable → Blocked/Waiting/Timed Waiting : 스레드가 락을 얻지 못하거나, wait() 또는 sleep() 메서드를 호출할 때 해당 상태로 전이된다.
Blocked/Waiting/Timed Waiting → Runnable: 스레드가 락을 얻거나, 기다림이 완료되면 다 Runnable 상태로 돌아간다.
main 스레드를 통해 myThread 객체를 생성한다. 스레드 객체만 생성하고 아직 start() 를 호출하지않았기 때문에 NEW 상태이다.
state2 = RUNNABLE
myThread.start() 를 호출해서 myThread 를 실행 상태로 만든다. 따라서 RUNNABLE 상태가 된다.
참고로 실행 상태가 너무 빨리 지나가기 때문에 main 스레드에서 myThread 의 상태를 확인하기는 어렵
다. 대신에 자기 자신인 myThread 에서 실행 중인 자신의 상태를 확인했다.
state3 = TIMED_WAITING
Thread.sleep(3000) : 해당 코드를 호출한 스레드는 3000ms (3초)간 대기한다. myThread 가 해당코드를 호출했으므로 3초간 대기하면서 TIMED_WAITING 상태로 변한다.
참고로 이때 main 스레드가 myThread 의 TIMED_WAITING 상태를 확인하기 위해 1초간 대기하고 상태를 확인했다.
state4 = RUNNABLE
myThread 는 3초의 시간 대기 후 TIMED_WAITING 상태에서 빠져나와 다시 실행될 수 있는
RUNNABLE 상태로 바뀐다.
state5 = TERMINATED
myThread 가 run() 메서드를 실행 종료하고 나면 TERMINATED 상태가 된다.
myThread 입장에서 run() 이 스택에 남은 마지막 메서드인데, run() 까지 실행되고 나면 스택이 완전
히 비워진다. 이렇게 스택이 비워지면 해당 스택을 사용하는 스레드도 종료된다.
4️⃣ 체크 예외 재정의
Runnable 인터페이스의 run() 메서드를 구현할 때 InterruptedException 체크 예외를 밖으로 던질 수 없는 이유를 알아보자..
Runnable 인터페이스 내부
publicinterfaceRunnable {
voidrun();
}
체크 예외
부모 메서드가 체크 예외를 던지지 않는 경우, 재정의된 자식 메서드도 체크 예외를 던질 수 없다.
자식 메서드는 부모 메서드가 던질 수 있는 체크 예외의 하위 타입만 던질 수 있다.
언체크(런타임) 예외
예외 처리를 강제하지 않으므로 상관없이 던질 수 있다.
packagethread.control;
publicclassCheckedExceptionMain {
publicstaticvoidmain(String[] args) {
thrownewException();
}
staticclassCheckedRunnableimplementsRunnable {
@Overridepublicvoidrun() /*throws Exception*/ { // 주석 풀면 예외 발생// throw new Exception(); // 주석 풀면 예외 발생
}
}
}
main()은 체크 예외를 밖으로 던질 수 있다.
run()은 체크 예외를 밖으로 던질 수 없다.
예를 들어 다음 코드의 InterruptedException 도 체크 예외이므로 던질 수 없다. 컴파일 오류가 발생한다.
main 스레드에서 다음 코드를 실행하게 되면 main 스레드는 thread-1, thread-2가 종료될 때 까지 기다린다. 이때 main스레드는 WAITING상태가 된다.
thread1.join();
thread2.join();
Waiting (대기상태)
스레드가 다른 스레드의 특정 작업이 완료되기를 무기한 기다리는 상태이다.
join() 을 호출하는 스레드는 대상 스레드가 TERMINATED 상태가 될 때 까지 대기한다. 대상 스레드가TERMINATED 상태가 되면 호출 스레드는 다시 RUNNABLE 상태가 되면서 다음 코드를 수행한다.
하지만 join() 의 단점은 다른 스레드가 완료될 때 까지 무기한 기다리는 단점이 있다. 비유를 하자면 맛집에 한 번 줄을 서면 중간에 포기하지 못하고 자리가 날 때 까지 무기한 기다려야 한다. 만약 다른 스레드의 작업을 일정 시간 동안만 기다리고 싶다면 어떻게 해야할까?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
3. 스레드 제어와 생명 주기1
1️⃣ 스레드 기본 정보
myThread객체를 문자열로 변환하여 출력한다.Thread클래스의toString()메서드는 스레드 ID, 스레드 이름, 우선순위, 스레드 그룹을 포함하는 문자열을 반환한다.
Thread[#21,myThread,5,main]"myThread"라는 이름을 지정했기 때문에,이 값이 반환된다. 참고로 스레드 ID는 중복되지 않지만, 스레드 이름은 중복될 수 있다
getPriority(): 스레드의 우선순위를 반환하는 메서드이다. 우선순위는 1 (가장 낮음)에서 10 (가장 높음)까지의
값으로 설정할 수 있으며, 기본값은 5이다.
setPriority()메서드를 사용해서 우선순위를 변경할 수 있다.우선순위는 스레드 스케줄러가 어떤 스레드를 우선 실행할지 결정하는 데 사용된다. 하지만 실제 실행 순서는
JVM 구현과 운영체제에 따라 달라질 수 있다.
myThread 는 main 스레드에 의해 생성되었으므로 main 스레드가 부모 스레드이다. main 스레드는 기본으로 제공되는 main 스레드 그룹에 소속되어 있다. 따라서 myThread 도 부모 스레드인
main 스레드의 그룹인 main 스레드 그룹에 소속된다.
Thread.State열거형에 정의된 상 수 중 하나이다. 주요 상태는 다음과 같다.2️⃣ 스레드의 생명 주기 - 설명
1️⃣ New (새로운 상태)
2️⃣ Runnable (실행 가능 상태)
RUNNABLE상태이다. 자바에서 둘을 구분해서 확인할 수는 없다.3️⃣ Blocked (차단 상태)
4️⃣ Waiting (대기 상태)
5️⃣ Timed Waiting (시간 제한 대기 상태)
6️⃣ Terminated (종료 상태)
✅ 자바 스레드의 상태 전이 과정
3️⃣ 스레드의 생명 주기 - 코드
Thread.currentThread()를 호출하면 해당 코드를 실행하는 스레드 객체를 조회할 수 있다
Thread.sleep(): 해당 코드를 호출한 스레드는TIMED_WAITING 상태가 되면서 특정 시간 만큼 대기한다.
Thread.sleep()은 InterruptedException이라는 체크 예외를 던진다. 따라서 체크 예외를 잡아서 처 리하거나 던져야 한다.
run()메서드 안에서는 체크 예외를 반드시 잡아야 한다. 이 부분은 바로 뒤에서 설명한다.
InterruptedException은 인터럽트가 걸릴 때 발생하는데, 인터럽트는 뒤에서 알아본다. 지금은 체크 예외
가 발생한다 정도만 이해하면 충분하다.
결과
참고로 실행 상태가 너무 빨리 지나가기 때문에 main 스레드에서 myThread 의 상태를 확인하기는 어렵
다. 대신에 자기 자신인 myThread 에서 실행 중인 자신의 상태를 확인했다.
RUNNABLE 상태로 바뀐다.
히 비워진다. 이렇게 스택이 비워지면 해당 스택을 사용하는 스레드도 종료된다.
4️⃣ 체크 예외 재정의
Runnable 인터페이스의 run() 메서드를 구현할 때 InterruptedException 체크 예외를 밖으로 던질 수 없는 이유를 알아보자..
Runnable 인터페이스 내부
main()은 체크 예외를 밖으로 던질 수 있다.
run()은 체크 예외를 밖으로 던질 수 없다.
예를 들어 다음 코드의
InterruptedException도 체크 예외이므로 던질 수 없다. 컴파일 오류가 발생한다.✅체크 예외 재정의 규칙
****✅ 안전한 예외 처리
➡️ Sleep 유틸리티
5️⃣ join - 시작
앞서 Thread.sleep() 메서드를 통해 TIMTED_WAITING 상태를 알아보았다. 이번에는 join() 메서드를 통해 WAITING(대기 상태)가 무엇이고 왜 필요한지 알아보자.
Waiting(대기 상태)
예제를 통해서 알아보자.
JoinMainV0
위 코드에서의 핵심
그렇다면 main 스레드가 가장 마지막에 종료하게 하려면 어떻게 해야할까?
예제를 통해서 알아보자.
6️⃣ join - 필요한 상황
이 코드는 스레드를 하나만 사용하기 때문에 CPU 코어도 하나만 사용할 수 있다. CPU 코어를 더 효율적으로 사용하려면 여러 스레드로 나누어 계산하면 된다.
1 ~ 100 까지 더한 결과는 5050 이다. 이 연산은 다음과 같이 둘로 나눌 수 있다.
1 ~ 50 까지 더하기 = 127551 ~ 100 까지 더하기 = 3775
두 계산 결과를 합하면 5050 이 나온다.
main 스레드가 1 ~ 100으로 더하는 작업을 thread-1 , thread-2 에 각각 작업을 나누어 지시하면 CPU 코어를 더 효율적으로 활용할 수 있다. CPU 코어가 2개라면 이론적으로 연산 속도가 2배 빨라진다.
JoinMainV1
그런데 실행 결과를 보면 기대와 다르게 task1.result , task2.result 모두 0으로 나온다. 그리고 `task1 +task2의 결과도 0으로 나온다. 계산이 전혀 진행되지 않았다. 이 부분을 자세히 분석해보자.
main
스레드는thread-1,thread2에 작업을 지시하고,thread-1,thread2` 가 계산을 완료하기도 전에 먼저 계산 결과를 조회했다.참고로 thread-1 , thread-2 가 계산을 완료하는데는 2초 정도의 시간이 걸린다.
따라서 결과가 task1 + task2 = 0으로 출력된다.
메모리 구조로 구체적으로 보게되면
thread-1은x001인스턴스의run()메서드를 실행한다.thread-2는x002인스턴스의run()메서드를 실행한다.main스레드는 두 스레드를 시작한 다음에 바로task1.result,task2.result를 통해 인스턴스에 있는 결과 값을 조회한다.린다.
7️⃣ join - sleep 사용
join()메서드를 사용하면 깔끔하게 문제를 해결할 수 있다.8️⃣ join - join사용
하지만
join()의 단점은 다른 스레드가 완료될 때 까지 무기한 기다리는 단점이 있다. 비유를 하자면 맛집에 한 번 줄을 서면 중간에 포기하지 못하고 자리가 날 때 까지 무기한 기다려야 한다. 만약 다른 스레드의 작업을 일정 시간 동안만 기다리고 싶다면 어떻게 해야할까?9️⃣ join - 특정 시간 만큼만 대기
다.
🔟 문제와 풀이
1️⃣ 다음 코드를 작성하고, 코드를 실행하기 전에 로그가 어떻게 출력될지 예측해 보자. 그리고 총 실행 시간이 얼마가 걸릴 예측해보자
2️⃣ join - 활용 2
All reactions