[Java] 멀티 스레드 ②

kiteB·2022년 2월 11일
0

Java2

목록 보기
2/36
post-thumbnail

[ 스레드 우선순위 ]

1. 동시성과 병렬성

멀티 스레드는 동시성 또는 병렬성으로 실행된다.

✅ 동시성 ( Concurrency )

동시에 실행되는 것처럼 보이는 것

  • 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아가며 실행하는 성질을 말한다.
  • 싱글 코어 CPU를 이용한 멀티 스레드 작업은 병렬적으로 실행되는 것처럼 보이지만, 사실은 번갈아가며 실행하는 동시성 작업이다. 번갈아 실행하는 것이 워낙 빠르다보니 병렬성으로 보일 뿐이다.

✅ 병렬성 ( Parallelism )

실제로 동시에 여러 작업이 처리되는 것

  • 병렬성은 멀티 작업을 위해 멀티 코어에서 개별 스레드를 동시에 실행하는 성질을 말한다.

스레드의 개수가 코어의 수보다 많을 경우, 스레드를 어떤 순서에 의해 동시성으로 실행할 것인가를 결정해야 하는데, 이것을 스레드 스케줄링이라고 한다. 스레드 스케줄링에 의해 스레드들은 아주 짧은 시간에 번갈아가면서 그들의 run() 메소드를 조금씩 실행한다.


2. 스레드 스케줄링

자바의 스레드 스케줄링은 우선순위 방식과 순환 할당 방식을 사용한다.

✅ 우선순위 방식 ( Priority )

우선순위가 높은 스레드가 실행 상태를 더 많이 가지도록 스케줄링하는 것

  • 스레드 우선순위 방식은 스레드 객체에 우선순위 번호를 부여할 수 있기 때문에 개발자가 코드로 제어할 수 있다.
  • 우선순위 방식에서 우선순위는 1에서부터 10까지 부여되는데, 1이 가장 우선순위가 낮고, 10이 가장 높다.
    • 우선순위를 부여하지 않으면 모든 스레드들은 기본적으로 5의 우선순위를 할당받는다.
    • 만약 우선순위를 변경하고 싶다면 Thread 클래스가 제공하는 setPriority() 메소드를 이용하면 된다.
      thread.setPrioity(우선순위);
  • 우선순위의 매개값으로 1~10까지의 값을 직접 주어도 되지만, 코드의 가독성(이해도)을 높이기 위해 Thread 클래스의 상수를 사용할 수도 있다.
    thread.setPriority(Thread.MAX_PRIORITY);	//10
    thread.setPriority(Thread.NORM_PRIORITY);	//5
    thread.setPriority(Thread.MIN_PRIORITY);	//1
    • 다른 스레드에 비해 실행 기회를 더 많이 가지려면 MAX_PRIORITY로 우선순위를 높게 설정하면 된다. 동일한 계산 작업을 하는 스레드들이 있고, 싱글 코어에서 동시성으로 실행할 경우, 우선 순위가 높은 스레드가 실행 기회를 더 많이 가지기 때문에 낮은 스레드보다 계산 작업을 빨리 끝낸다.
  • 쿼드 코어일 경우에는 4개의 스레드가 병렬성으로 실행될 수 있기 때문에 4개 이하의 스레드를 실행할 경우에는 우선순위 방식이 크게 영향을 미치지 못한다. 최소한 5개 이상의 스레드가 실행되어야 우선순위의 영향을 받는다.

✅ 순환 할당 방식 ( Round-Robin )

시간 할당량(Time Slice)을 정해서 하나의 스레드를 정해진 시간만큼 실행하고 다시 다른 스레드를 실행하는 방식

  • 자바 가상 기계에 의해서 정해지기 때문에 코드로 제어할 수 없다.

[ 동기화 메소드과 동기화 블록 ]

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

싱글 스레드 프로그램에서는 한 개의 스레드가 객체를 독차지해서 사용하면 되지만,
멀티 스레드 프로그램에서는 스레드들이 객체를 공유해서 작업해야 하는 경우가 있다.

이 경우, 스레드 A를 사용하던 객체가 스레드 B에 의해 상태가 변경될 수 있기 때문에 스레드 A가 의도했던 것과는 다른 결과를 산출할 수도 있다.

User1 스레드가 Calculator 객체의 memory 필드에 100을 먼저 저장하고 2초간 일시 정지 상태가 된다. 그동안에 User1 스레드가 memory 필드값을 50으로 변경한다. 2초가 지나 User1 스레드가 다시 실행 상태가 되어 memory 필드의 값을 출력하면 User2가 저장한 50이 나온다.


2. 동기화 메소드 및 동기화 블록

스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없도록 하려면 스레드 작업이 끝날 때까지 객체에 잠금을 걸어서 다른 스레드가 사용할 수 없도록 해야 한다.

멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역을 임계 영역(critical section)이라고 한다. 자바는 임계 영역을 지정하기 위해 동기화(synchronized) 메소드와 동기화 블록을 제공한다.

스레드가 객체 내부의 동기화 메소드 또는 블록에 들어가면 즉시 객체에 잠금을 걸어 다른 스레드가 임계 영역 코드를 실행하지 못하도록 한다. 동기화 메소드를 만드는 방법은 다음과 같이 메소드 선언에 synchronized 키워드를 붙이면 된다. synchronized 키워드는 인스턴스와 정적 메소드 어디든 붙일 수 있다.

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

동기화 메소드는 메소드 전체 내용이 임계 영역이므로 스레드가 동기화 메소드를 실행하는 즉시 객체에는 잠금이 일어나고, 스레드가 동기화 메소드를 실행 종료하면 잠금이 풀린다. 메소드 전체 내용이 아니라, 일부 내용만 임계 영역으로 만들고 싶다면 다음과 같이 동기화(synchronized) 블록을 만들면 된다.

public void method() {
    //여러 스레드가 실행 가능 영역
    
    ...
    
    //동기화 블록
    synchronized(공유객체) {	//공유 객체가 객체 자신이면 this를 넣을 수 있다.
        //임계 영역
        //단 하나의 스레드만 실행
    }
}

동기화 블록의 외부 코드들은 여러 스레드가 동시에 실행될 수 있지만, 동기화 블록의 내부 코드는 임계 영역이므로 한 번에 하나의 스레드만 실행될 수 있고 다른 스레드는 실행할 수 없다. 만약 동기화 메소드와 동기화 블록이 여러 개 있을 경우, 스레드가 이들 중 하나를 실행할 때 다른 스레드는 해당 메소드는 물론이고 다른 동기화 메소드 및 블록도 실행할 수 없다. 하지만 일반 메소드는 실행이 가능하다.


[ 참고자료 ]

이것이 자바다 책
동시성, 병렬성 - https://seamless.tistory.com/42

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글