Java 프로그램은 하나의 프로세스로 만들어져 실행됨
→ 프로세스는 프로그램의 통상적 실행 단위
프로세스는 자원을 확보하고 있는 실행 중인 프로그램
지금까지는 프로세스에서 하나의 스레드가 생성되고, main() 메소드가 호출되어 실행됨 (단일 스레드)
프로세스 내에 존재하는 소규모 실행 흐름
하나의 프로세스 내에서 동시 실행을 위해 존재하는 여러 스레드
Java 프로그램은 하나의 스레드(main 스레드)로 시작됨
main 스레드에서 자식 스레드를 만들고 시작할 수 있음Thread 클래스스레드의 생성과 관리를 위한 메소드 제공
Thread 클래스의 객체가 필요함Thread 생성 방식)| 생성자 | 설명 |
|---|---|
Thread() | 새로운 스레드를 생성하며, 이름이 자동으로 “Thread-n”으로 주어짐 |
Thread(String name) | 새로운 스레드를 생성하며, 스레드의 이름을 name으로 지정 |
Thread(Runnable target) | 새로운 스레드를 생성하며, 스레드의 이름이 자동으로 주어짐. 스레드가 실행될 때 target 객체의 run() 메소드가 실행됨 |
Thread(Runnable target, String name) | 스레드의 이름을 name으로 지정하며, 나머지는 위와 같음 |
Thread 관련 메서드)| 메서드 형식 | 설명 |
|---|---|
static Thread currentThread() | 현재 실행 중인 스레드 객체의 참조값을 리턴 |
String getName() | this 스레드의 이름을 리턴 |
void setName(String name) | this 스레드의 이름을 name으로 변경 |
int getPriority() | this 스레드의 우선순위를 리턴 |
void setPriority(int newPriority) | this 스레드의 우선순위를 newPriority로 변경 |
void start() | run()을 호출하여 this 스레드를 실행시킴 |
Thread 유형의 객체 t를 생성
t.start()를 호출
→ 스레드의 실행 시작, run() 메소드 호출함
run() 메소드에는 스레드의 실행 코드가 있음
→ run() 메소드를 정의하는 두 가지 방법
Thread 클래스를 상속받는 클래스Thread 클래스를 상속받는 클래스 A를 정의
→ 여기서void run()메소드 재정의
start()를 호출
Runnable 인터페이스를 구현한 클래스Runnable 인터페이스를 구현하는 클래스 B를 정의
→ 여기서void run()메소드 구현
start()를 호출함
멀티 스레드 프로그램의 실행 결과는 예측할 수 없음
→ 실행 결과가 매번 다를 수 있음
각 스레드는 정해진 순서 없이 독립적으로 실행됨
main 스레드는 다른 스레드를 시작하거나, 다른 스레드의 실행과 무관하게 실행되고 종료됨

생성된 스레드가
CPU를 얻어 실행되고 최종적으로 종료될 때까지 여러 상태 변화를 겪음
| 상태 | 설명 |
|---|---|
| Startable | 객체가 생성되었으나 start()의 실행 전 상태 |
| Runnable | start() 메서드가 호출되었으나 CPU를 아직 획득하지 못한 상태 |
| Running | CPU를 얻어 실행 중인 상태 |
| Not Running | CPU를 잃고 중단된 상태 (Blocked, Waiting, Timed_Waiting 포함) |
| Dead | run() 메서드가 종료된 상태 |

// 스레드의 우선순위 변경 → 높은 우선순위 가진 스레드가 `CPU` 얻음
void setPriority(int newPriority)
// 현재 실행 중인 스레드가 정해진 시간 동안 실행을 멈추고 `Not Running` 상태가 됨
// 다른 스레드가 이 스레드를 `interrupt()` 메서드로 깨우면 예외 발생
static void sleep(long millis) throws InterruptedException
// 현재 실행 중인 스레드가 잠시 실행을 멈추고 `Runnable` 상태로 들어감
// CPU를 다른 스레드에게 양보하는 것
static void yield()
// 스레드가 종료될 때까지 기다림
// 현재 실행 중이었던 스레드는 `Not Running` 상태로 들어감
// void join(long millis)는 최대 millis 시간 동안 기다림
// 기다리는 중에 다른 스레드가 이 스레드를 깨워주면,
// InterruptedException을 받으면서 리턴됨
void join() throws InterruptedException
// 스레드를 인터럽트 시킴
// 스레드가 wait(), join(), sleep()에 의해 중단된 상태였다면
// 그 상태에서 깨어나 Runnable 상태가 됨
void interrupt()
Object 클래스의 메소드// 객체를 처리 중인 스레드가 대기 상태로 감
// 다른 스레드가 해당 객체에 대해 notify() 메소드를 호출할 때까지 기다림
void wait() throws InterruptedException
// 객체를 처리 중인 스레드를 정해진 시간 동안 대기 상태로 만듬
// 다른 스레드가 해당 객체에 대해 notify() 메소드를 실행시켜 주면,
// 대기 중이라도 이 스레드가 깨어날 수 있음
// *이 메소드는 synchronized 메소드의 내부에서만 호출 가능*
void wait(long millis) throws InterruptedException
// wait()를 호출하여 대기 중인 스레드를 깨워 줌
// *이 메소드는 synchronized 메소드의 내부에서만 호출 가능*
void notify()
여러 개의 스레드들이 하나의 공유 객체에 동시 접근하는 경우 데이터 무결성이 훼손됨

서로 다른 스레드들이 공유 자원을 다룰 때, 데이터 무결성을 보장하도록 하는 것
💡 동기화 방법
- 상호 배제 원칙
- 키워드:
synchronized
- 동기화 메소드 또는 동기화 블록 제공
- 공유 자원을 수정할 때, 다른 스레드에서 같은 코드를 수행할 수 없게 함 (락 설정)
synchronized 메소드스레드 동기화를 위한 키워드로, 한 번에 하나의 스레드에 의해서만 실행 가능하게 함
synchronized 메소드를 실행하려면 메소드를 호출한 객체에 대한 lock을 얻어야 함
lock을 얻을 때 까지 동일 객체의 synchronized 메소드를 실행할 수 없고 대기해야 함 public synchronized void func() { ... }
일부 블록만 동기화하는 것도 가능함
synchronized(객체) { ... }
this를 사용synchronized 메소드 사용 예class Counter {
private int c = 0;
public synchronized void increment() { c++; }
public synchronized void decrement() { c--; }
public int value() { return c; }
}
class Counter {
private int c = 0;
public void increment() {
synchronized(this) { c++;}
}
public void decrement() {
synchronized(this) { c--;}
}
public int value() { return c; }
}