-
[Java 자바] 12. 멀티 스레드 ② 동기화, 스레드 상태와 제어Programming/Java 2022. 9. 12. 15:19반응형
12-4. 동기화 메소드와 동기화 블록
12-4-1. 공유 객체를 사용할 때 주의점
- 싱글 스레드 프로그램에서는 한 개의 스래드가 객체를 전부 사용하지만,
멀티 스레드 프로그램에서는 스레드들이 객체를 공유해서 작업해야 하는 경우 발생- 이 경우, 다른 스레드에 의해 객체가 상태 변경이 되어 의도와 다른 결과가 산출될 수 있기 때문에 주의해야 함
12-4-2. 동기화 메소드 및 동기화 블록
- 임계 영역 (critical section): 멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역
=> 자바에서는 이를 지정하기 위해 동기화 메소드와 동기화 블록을 제공
=> 스레드가 객체 내부의 동기화 메소드 또는 블록에 들어가면 즉시 객체에 잠금을 걸어 다른 스레드가 임계 영역의 코드를 실행하지 못 함
// 1. 동기화 메소드 만들기 (synchronized 키워드 활용) public synchronized void method() { 임계 영역; // 단 하나의 스레드만 실행 } // 2. 동기화 블록 (메소드의 일부 내용만 임계 영역으로 만들 경우) public void method() { // 여러 스레드가 실행 가능한 영역 ... synchronized(공유객체) { // 공유객체가 자신이면 this 삽입 가능 임계 영역 // 단 하나의 스레드만 실행 } // 여러 스레드가 실행 가능한 영역 ... }
12-5. 스레드 상태
- 실행 대기: start() 메소드 호출 (스케줄링이 되지 않아 실행을 기다리는 상태)
- 실행: 스레드 스케줄링으로 선택된 스레드가 CPU를 점유하고 run() 메소드를 실행
=> 실행 대기와 실행을 번갈아가면서 스레드의 run() 메소드가 조금씩 실행됨
- 종료: 더 이상 실행할 코드가 없는 상태
- 일시정지: 스레드가 실행할 수 없는 상태
// getState() 메소드를 통해 스레드 상태에 대한 열거 상수를 리턴받을 수 있음 Thread.State state = targetThread.getState();
상태 열거 함수 설명 객체 생성 NEW 스레드 객체가 생성, 아직 start() 메소드가 호출되지 않은 상태 실행 대기 RUNNABLE 실행 상태로 언제든지 갈 수 있는 상태 일시 정지 WAITING 다른 스레드가 통지할 때까지 기다리는 상태 TIMED_WAITING 주어진 시간 동안 기다리는 상태 BLOCKED 사용하고자 하는 객체의 락이 풀릴 때까지 기다리는 상태 종료 TERMINATED 실행을 마친 상태 12-6. 스레드 상태 제어
: 미디어 플레이어에서 동영상을 보다가 일시 정지 시키거나 종료시킬 수도 있는 것처럼, 스레드의 상태를 변경하는 것
12-6-1. 주어진 시간 동안 일시 정지 (sleep())
- 실행 중인 스레드를 일정 시간 멈추게 하고 싶을 때 (밀리세컨드 단위로 입력)
try { Thread.sleep(1000); } catch(InterruptedException e) { // 일시 정지 상태에서 주어진 시간이 되기전에 interrupt() 메소드가 호출되면 실행 }
12-6-2. 다른 스레드에게 실행 양보 (yield())
- 반복문들이 무의미한 반복을 계속할 경우, 다른 스레드에게 실행을 양보하고 자신은 실행 대기 상태로 가게 하는 것
public void run() { while(true) { if(work) { System.out.println("ThreadA 작업 내용") } else { Thread.yield(); } } }
12-6-3. 다른 스레드의 종료를 기다림 (join())
- 다른 스레드가 종료될 때까지 기다렸다가 실행해야 하는 경우 사용 (다른 스레드의 계산 결과값을 활용해야할 때 등)
try { sumThread.join(); // sumThread가 종료될 때까지 메인스레드를 일시 정지 } catch (InterruptedException e) { }
12-6-4. 스레드 간 협업 (wait(), notify(), notifyAll())
- 경우에 따라 두 개의 스레드를 교대로 번갈아며 실행해야 할 경우, 공유 객체를 활용
- 공유 객체는 두 스레드가 작업할 내용을 각각 동기화 메소드로 구분해 놓음
1) 한 스레드가 작업을 완료하면 notify() 메소드를 호출해 일시 정지 상태의 다른 스레드를 실행 대기 상태로 만듦
2) 자신은 두 번 작업하지 않도록 wait() 메소드를 호출하여 일시 정지 상태로 만듦
( wait(long timeout) 이나 wait(long timeout, int nanos)를 활용하면 자동으로 시간이 지나면 실행 대기 상태가 됨)
// WorkObject.java public class WorkObject { public synchronized void methodA() { System.out.println("ThreadA의 methodA() 작업 실행"); notify(); try { wait(); } catch {InterruptedException e) { } } public synchronized void methodB() { System.out.println("ThreadB의 methodB() 작업 실행"); notify(); try { wait(); } catch {InterruptedException e) { } } } // ThreadA.java public class ThreadA extends Thread { private WorkObject workobject; public ThreadA(WorkObject workObject) { this.workObject = workObject; } @Override public void run() { for(int i = 0; i < 10; i++) { workObject.methodA(); } } } // ThreadB.java public class ThreadB extends Thread { private WorkObject workobject; public ThreadB(WorkObject workObject) { this.workObject = workObject; } @Override public void run() { for(int i = 0; i < 10; i++) { workObject.methodB(); } } } // WaitNotifyExample.java public class WaitNotifyExample { public static void main(String[] args) { WorkObject sharedObject = new WorkObject(); ThreadA threadA = new ThreadA(sharedObject); ThreadB threadB = new ThreadB(sharedObject); threadA.start(); threadB.start(); } }
12-6-5. 스레드의 안전한 종료 (stop 플래그, interrupt())
① stop 플래그를 이용하는 방법
- run() 메소드가 정상적으로 종료되도록 유도하는 것
public class XXXThread extends Thread { private boolean stop; // 스탑 플래그 필드 public void run() { while(!stop) { 스레드가 반복 실행하는 코드; } // 스레드가 사용한 자원 정리 } }
② interrupt() 메소드를 이용하는 방법
- 스레드가 일시 정지 상태에 있을 때 InterruptedException 예외를 발생시키는 역할
// InterruptExample.java public class InterruptExample { public static void main(String[] args) { Thread thread = new PrintThread2(); thread.start(); try { Thread.sleep(1000);} catch (InterruptedException e) {} thread.interrupt(); } } // PrintThread.java public class PrintThread extends Thread { public void run() { try { while(true) { System.out.println("실행 중"); Thread.sleep(1); } } catch(InterruptedException e) { } System.out.println("자원 정리"); System.out.println("실행 종료"); } }
- interrupt() 호출 여부 확인하는 메소드
boolean status = Thread.interrupted(); boolean status = objThread.isInterrupted();
반응형'Programming > Java' 카테고리의 다른 글
[Java 자바] 12. 멀티 스레드 ④ 스레드풀 (0) 2022.09.12 [Java 자바] 12. 멀티 스레드 ③ 데몬 스레드, 스레드 그룹 (0) 2022.09.12 [Java 자바] 12. 멀티 스레드 ① 개념과 생성방법, 우선순위 (0) 2022.09.12 [Java 자바] 11. 기본 API 클래스 ⑧ Wrapper(포장), Math, Random 클래스 (0) 2022.09.04 [Java 자바] 11. 기본 API 클래스 ⑦ Arrays 클래스 (0) 2022.09.04