자바

week4: 자바 Thread -2

aerimi-code 2025. 10. 1. 01:30

 

멀티 쓰레드의 사용을 생각해보자

테트리스 프로그램을 구상해보면

최소 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