멀티 쓰레드의 사용을 생각해보자
테트리스 프로그램을 구상해보면
최소 3개의 쓰레드가 필요하다. (오디오 재생, 블록 아래 움직이는 코드, 키 입력을 받아 블록의 방향을 바꾸는 코드)
JVM은 3개의 쓰레드 중 하나를 선택하여 실행시킨다.
JVM이 쓰레드 A를 실행하는 중 B를 실행시키려면 A를 일시 중단하고, B를 호출해야한다.
실행 상황
1. Thread 클래스를 이용하여 새로운 Thread객체가 생성된다.
2. start()를 통해 생성된 Thread를 실행한다.
=> 실행 가능 상태 돌입
3. Thread가 스케쥴링 큐에 넣어지고 스케줄러에 의해 우선위에 따라 실행된다.
실행 중 일시 중단
wait(), sleep(), 입출력 작업을 위해 대기하는 경우
안전한 멀티 프로세싱을 위해서는 정교한 상태 제어가 필요하다.
문제발생: 계좌에 접근을 할 때, 10000원이 있는 계좌에서 동시에 두 사람이 1000원을 뺀다고 하고, 두명 다 10000원의 계좌를 읽고, 뺀다면 실제로는 2000원이 빠져나간 것이지만, 컴퓨터는 1000원만 빠져나갔다고 기록할 수 있다.
배타적 접근 보장 ! : 다수의 공유 데이터에 동시에 접근하는 경우, 스레드 동기화를 통해 공유 데이터에 접근하는 모든 스레드를 한줄로 세우고, 한 스레드가 작업을 끝낼 때 까지 다른 쓰레드가 대기하도록 한다.
Sychronized (동기화 시키기)
특정 코드 블럭이나 메소드를 임계 영역으로 만든다.
임계영역 : 두개 이상의 쓰레드가 동시에 접근해서는 안되는 공유자원 부분
하나의 쓰레드가 synchronized로 보호된 코드 영역에 들어가면, 해당 코드 블록이 포함 된 객체에 락을 건다. 다른 스레드 들은 이 락이 풀릴 때까지 해당 코드 영역에 접근할 수 없고, 대기해야한다.
=> 경쟁 상태를 막아준다.
사용법:
1. 동기화 메소드 (Synchronized Method)
메소드 선언 자체에 Synchronized를 붙이기 => 해당 메소드가 포함된 객체 자체(this)가 락의 대상이 된다.
synchronized void deposit (int amount) {
this.balance +=amount;
}
synchronized void withDraw(int amount) {
this.balance -=amount;
}
여기서 deposit과 withDraw는 sychronized로 선언되었기 때문에, 여러 쓰레드가 동시에호출하더라도 하나의 쓰레드만 입금하고 인출할 수 있다.
락의 효과: 다른 스레드는 그 객체의 다른 synchronized 메소드/코드 블록에 접근할 수 없게 된다.
Lab: 가족공유계좌
depositor.start(); // 예금자 실행
withdrawer.start(); // 인출자 실행
depositor.join(); // 예금자 종료까지 대기
withdrawer.join(); // 인출자 종료까지 대기
이 코드가 실행되면, depositor 스레드와 withdrawer 스레드가 각각 독립적으로 작업을 시작
즉시 다음 코드로 넘어가고, 스레드의 작업이 끝날 때까지 기다리지 않는다.
=> 예금과 인출 작업이 거의 동시에 병렬로 실행될 수 있음!
join() 메소드는 해당 스레드가 끝날 때까지 기다리라는 명령
- depositor.join();이 호출되면, 메인 스레드는 depositor 스레드의 작업이 완전히 끝날 때까지 그 자리에서 실행을 멈추고 대기합니다.
- 마찬가지로 withdrawer.join();은 withdrawer 스레드가 종료될 때까지 메인 스레드를 대기시킵니다.
- 결과적으로, 이 두 줄의 코드는 예금과 인출 작업이 모두 안전하게 종료되는 것을 보장
두 쓰레드 중 뭐가 먼저 끝날지 모르니까 둘다 join을 붙여준다.
효과-> 모든 계산이 완료된 후의 정확하고 신뢰할 수 있는 최종 잔액이 출력
System.out.println("최종 잔액: " + account.getBalance());
: 해당 쓰레드가 완료될 때 까지 다른 쓰레드가 기다리게 한다.
2가지 형태 - join(), join(long mills)
계산 작업을 하는 쓰레드가 모든 계산을 마쳤을 때, 결과값을 받아 이용해야 하는 경우 주로 사용.
상태 제어: sleep() 과 wait()
sleep() : 일정시간동안 쓰레드 일시중지
락을 유지한 채 지정 시간이 지나면 자동 재개
일시 정지 상태에서 interrput() 메소드를 호출한다.
wait() : 다른 쓰레드의 신호를 기다리며 일시중지
누군가가 깨워줄 때 까지 잔다.
object클래스에 소속
락을 반납한 채, 누군가 notify(), nofifyAll()해줄 때까지 기다림
락(Lock):
여러 쓰레드가 하나의 자원에 접근할 때 사용.
락을 가진 쓰레드만 실행 가능. 없으면 기다려야함.
lab8 : 잠자는 숲속의 공주 wait(), notify()
'자바' 카테고리의 다른 글
| week9.java GUI_Swing, Event 실습 (0) | 2025.11.02 |
|---|---|
| week5: 자바 SOLID원칙 (0) | 2025.10.03 |
| week4: 자바 Thread (0) | 2025.09.27 |
| week3. 자바 Collections (set,list,map ) (0) | 2025.09.23 |
| week2: 자바 프로그래밍 (static, final, 싱글톤) (0) | 2025.09.19 |