Language/JAVA

열여섯번째날 [멀티 스레드(2) - 동기화 메소드 / 동기화 블록 / 스레드 상태 / 데몬 스레드 / 스레드 그룹 / 스레드 풀]

구일일구 2022. 8. 12. 19:14
반응형

목차

1. 동기화 메소드와 동기화 블록

2. 스레드 상태

3. 데몬 스레드

4. 스레드 그룹

5. 스레드 풀 

* 스레드 목적 : 여러개의 작업을 동시에, 병렬적으로. 


동기화 메소드와 동기화 블록

공유 객체를 사용할 때 주의할 점

* 멀티 스레드가 하나의 객체를 공유해서 생기는 오류

User1의 memory가 50이 되어 버림

 

동기화 메소드 및 동기화 블록 : synchronized

* 스레드가 사용중인 객체를 다른 스레드가 변경할 수 없도록 작업이 끝날때까지 객체에 잠금을 건다.

* 단 하나의 스레드만 실행할 수 있는 메소드 또는 블록

* 다른 스레드는 메소드나 블록 실행이 끝날 때까지 대기해야 함

* 임계 영역(critical section) : 단 하나의 스레드만 실행할 수 있는 코드 영역

* 임계 영역을 지정하기 위해 동기화 메소드 & 동기화 블록을 제공

 

* 동기화 메소드

public synchronized void method(){
    임계 영역; 	//단 하나의 스레드만 실행
}

 

* 동기화 블록

public void method(){
    //여러 스레드가 실행 가능 영역
    ...
    synchronized(공유하는 객체){
       임계영역 //단 하나의 스레드만 실행
    }
    //여러 스레드가 실행 가능 영역
    ...
}

 

User1 의 메모리 = 100 / User2의 메모리는 50


스레드 상태

* 일반적인 상태

스레드의 일반적인 상태

 

* 스레드에 일시정지 상태를 도입한 경우

 

* 스레드 상태에 대한 설명과 열거 상수들


스레드 상태 제어

* 실행 중인 스레드의 상태를 변경하는 것

* 상태 변화를 가져오는 메소드의 종류 : 취소선 가진 메소드는 사용X

 

주어진 시간동안 일시 정지 : sleep()

try{
    Thread.sleep(1000);
}catch(InterruptedException e){
    //interrupt() 메소드가 호출되면 실행
}

* 얼마 동안 일시 정지 상태로 있을 것인지 밀리세컨드(1/1000) 단위로 지정

* 일시 정지 상태에서 interrupt() 메소드 호출 : InterruptedException 발생함

 

다른 스레드에게 실행 양보 : yield()

* 무의미한 반복을 하는 스레드일 경우 : 다른 스레드에게 실행 양보, 자신은 실행 대기 상태로 가는 것

public void run(){
    while(true){
        if(work){
            System.out.println("ThreadA 작업 내용");
        }else{
            Thread.yield();
        }
    }
}

 

다른 스레드의 종료를 기다림 : join()

* 계산 작업을 하는 스레드가 모든 계산 작업 마쳤을 때, 결과값을 받아 이용하는 경우 주로 사용

 

스레드 간 협업: wait(), notify(), notifyAll()

* 두 개의 스레드가 교대로 번갈아 가며 실행해야 할 경우 주로 사용함

 

* 동기화 메소드 또는 블록에서만 호출 가능한 Object의 메소드

 

* 두 개의 스레드가 교대로 번갈아가며 실행해야 할 경우 주로 사용

 

스레드의 안전한 종료 : stop플래그, interrupt()

* 경우에 따라 실행 중인 스레드를 즉시 종료해야 할 필요가 있을 때 사용

 

* stop() 메소드 사용시

- 스레드가 즉시 종료되는 편리함이 있음

- Deprecated : 사용 중이던 자원들이 불안전한 상태로 남겨짐

 

* stop 플래그 이용하는 방법

- 플래그 : true, false를 이용함

- stop플래그로 메소드의 정상 종료 유도

private boolean stop;	//stop 플래그 필드

public void run(){
    while(!stop){		//stop이 true가 되면 run()이 종료됨
        스레드가 반복 실행하는 코드;
    }
    //스레드가 사용한 자원 정리
}

 

* interrupt() 메소드 이용하는 방법

- 스레드가 일시 정지일 상태일 경우 InterruptedException 발생시킴

- 실행 대기 또는 실행상태에서는 InterruptedException 발생하지 않음

- 일시 정지 상태로 만들지 않고 while문 빠져나오는 방법으로도 사용됨


데몬 스레드

* 주 스레드의 작업을 돋는 보조적인 역할을 수행하는 스레드

* 주 스레드가 종료되면, 데몬 스레드도 강제적으로 자동 종료

 

* 스레드를 데몬 스레드로 만들기

- 주 스레드가 데몬이 될 스레드의 setDaemon(true)호출

- 반드시 start() 메소드 호출 전에 setDaemon(true) 호출 : 그렇지 않으면 IllegalThreadStateException 발생

public static void main(Stirng[] args{
    AutoSaveThread thread = new AutoSaveThread();
    thread.setDaemon(true);
    thread.start();
    ...
}

 

* 현재 실행중인 스레드가 데몬 스레드인지 구별법

- isDaemon() 메소드 리턴값 조사 : 데몬 스레드일 경우 true 리턴


스레드 그룹

* 관련된 스레드를 묶어 관리 목적으로 이용

* 스레드 그룹은 계층적으로 하위 스레드 그룹 가질 수 있음

 

* 자동 생성되는 스레드 그룹

- system 그룹 : JVM 운영에 필요한 스레드들 포함

- system / main 그룹 : 메인 스레드 포함

 

* 스레드는 반드시 하나의 스레드 그룹에 포함

- 기본적으로 자신을 생성한 스레드와 같은 스레드 그룹

- 스레드 그룹에 포함시키지 않으면 기본적으로 system/main 그룹 

 

스레드 그룹 이름 얻기

* 현재 스레드가 속한 스레드 그룹 이름 얻기

ThreadGroup group = Thread.currentThread.getthreadGroup();
String groupName = group.getName();

 

* 프로세스 내에서 실행하는 모든 스레드에 대한 정보 얻기

- getAllStackTrace()는 Map 타입의 객체를 리턴

- 키는 스레드 / 값은 스레드 상태 기록을 가지고 있는 배열(StackTraceElement[])

Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();

 

스레드 그룹 생성

* 부모 그룹을 지정하지 않으면? 현재 속한 그룹의 하위 그룹으로 생성됨

ThreadGroup tg = new ThreadGroup(String name);
ThreadGroup tg = new ThreadGroup(ThreadGroup parent, String name);

 

스레드 그룹의 일괄 interrupt()

* 스레드 그룹의 interrupt() 호출 시 소속된 모든 스레드의 interrupt() 호출

ex) 10개의 스레드들을 모두 종료시키기 위해, 각 스레드에서 메소드를 10번 호출해도 되지만! 스레드들이 같은 그룹에 소속되어있으면 , 스레드 그룹의 interrupt() 메소드를 한번만 호출해주면 됨


스레드풀

* 스레드 폭증으로 일어나는 현상

- 병렬 작업 처리가 많아지면 스레드 개수 증가

- 스레드 생성과 스케줄링으로 인해 CPU가 바빠짐

- 메모리 사용량이 늘어남

- 애플리케이션의 성능 급격히 저하

 

* 스레드 풀(Thread Pool)

- 작업 처리에 사용되는 스레드를 제한된 개수만큼 미리 생성

- 작업 큐(Queue)에 들어오는 작업들을 하나씩 스레드가 맡아 처리

- 작업 처리가 끝난 스레드는 작업 결과를 애플리케이션으로 전달

- 스레드는 다시 작업 큐에서 새로운 작업을 가져와 처리

반응형