자바 기본 복습 10. 멀티쓰레드 프로그래밍

장난·2021년 6월 6일
0

자바 기본

목록 보기
10/15
post-thumbnail

10주차 과제: 멀티쓰레드 프로그래밍


📌 목표

자바의 멀티쓰레드 프로그래밍에 대해 학습하세요.


📌 학습할 것

  • Thread 클래스와 Runnable 인터페이스
  • 쓰레드의 상태
  • 쓰레드의 우선순위
  • Main 쓰레드
  • 동기화
  • 데드락

📜 시작에 앞서

  • 백기선 님의 라이브 스터디(2020년 11월부터 2021년 3월까지) 커리큘럼을 따라 진행한 학습입니다
  • 뒤늦게 알게 되어 스터디 참여는 못했지만 남아있는 스터디 깃허브 주소유튜브 영상을 참고했습니다

📑 Thread 클래스와 Runnable 인터페이스

  • 쓰레드 구현 방법
    • Thread 클래스를 상속
    • Runnable 인터페이스 구현

Thread 클래스

//Thread 클래스 상속
public class ThreadCreation extends Thread {
    
    @Override
    public void run(){
        //작업 내용
        System.out.println(Thread.currentThread().getName());
    }
    
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        
        ThreadCreation threadCreation = new ThreadCreation();
        
        threadCreation.start();
    }
}
/*
실행결과
main
Thread-0
*/
  • run() 외에도 오버라이드할 수 있는게 많다
  • extends 이미 했기 때문에 확장성 아쉽

Runnable 인터페이스

//Runnable 인터페이스 구현
class ThreadCreation1 implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        
        Runnable rannablThread = new ThreadCreation1();
        Thread threadCreation = new Thread(rannablThread);
        //위 두줄 한 줄로 하면
        //Thread threadCreation = new Thrad(new rannablThread());
        
        threadCreation.start();
    }
}

//Runnable 익명 클래스
class ThreadCreation2 {
    
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
    }
}

//Runnable 람다
class ThreadCreation3 {
    
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        new Thread(() -> System.out.println(Thread.currentThread().getName())).start();
    }
}
/*
실행결과
main
Thread-0
*/
  • run()만 오버라이드 가능
  • extends 가능

쓰레드 실행

  • start() 메서드로 쓰레드를 실행대기 상태로 만들며, 해당 쓰레드는 자기 차례가 되면 실행

threadrun

threadstart

출저: 자바의 정석


📑 쓰레드의 상태

  • 쓰레드의 상태는 getState() 메서드로 확인 가능하며, 리턴값은 Thread.State Enum
  • 쓰레드는 하나의 상태에만 속한다
  • Thread.State은 가상 머신에서의 상태이며 OS 쓰레드 상태를 반영하지 않는다

Thread.State

Enum Constant설명
NEW쓰레드가 시작되지 않은 상태
RUNNABLEJVM이 실행중인 상태(실행 대기 포함)
BLOCKEDlock이 풀리기를 기다리는 상태
WAITING다른 쓰레드가 특정 작업을 수행할 때까지 무기한 대기 중인 상태
TIMED_WAITING다른 쓰레드가 작업하도록 지정한 시간 동안 대기 중인 상태
TERMINATED쓰레드가 종료된 상태

threadstate

  • java.lang.Thread는 실행제어를 위한 다양한 메서드 제공
  • java.lang.Object에도 wait() notify() 등 쓰레드 실행제어 관련 메서드 제공

📑 쓰레드의 우선순위

  • 쓰레드의 우선순위는 쓰레드의 priority라는 멤버변수 값에 따라 결정
  • 쓰레드의 우선순위 관련 상수java.lang.Thread 필드
    • public static final int MAX_PRIORITY = 10 최대 우선순위 10
    • public static final int MIN_PRIORITY = 1 최소 우선순위 10
    • public static final int NORM_PRIORITY = 5
  • 쓰레드 우선순위 priority의 범위는 1~10
  • 쓰레드 우선순위가 높을 수록 상대적으로 더 많은 작업 시간을 할당 받는다
  • 쓰레드의 우선순위는 기본적으로 쓰레드를 생성한 쓰레드로부터 상속 받는다
  • 우선순위를 변경하려면 setPriority(int priority) 메서드 사용

📑 Main 쓰레드

  • 자바 프로그램을 실행하면 main쓰레드 자동으로 실행
    • 자동으로 생성되는 최초 쓰레드이기 때문에 이외 쓰레드는 모두 main쓰레드의 자식 쓰레드
    • main 쓰레드의 우선순위는 NORM_PRIORITY5이므로 자식 쓰레드도 기본값은 이와 같다
  • main쓰레드는 main() 메서드가 있는지 확인하고 실행
  • 일반적으로 메인쓰레드에서 여러 종료 작업을 수행하므로 마자막에 종료되는 쓰레드
    • 실행중인 사용자 쓰레드가 없을 때 프로그램이 종료된다

📑 동기화

  • 멀티쓰레드 프로세스는 여러 쓰레드가 프로세스 내의 공유 자원에 접근
  • 이때 한 쓰레드가 작업을 마치기 전에 다른 쓰레드가 동시에 같은 자원에 접근해 작업을 수행한다면 결과에 영향을 미침
  • 한 쓰레드가 사용중인 공유 자원에 대한 다른 쓰레드의 조작을 막는 것이 동기화
    • 이렇게 하나의 쓰레드만 특정 자원에 접근 허용할 코드 영역을 임계 영역(critical section)이라 한다
    • 이때 하나의 쓰레드만 자원에 접근할 수 있게 하는 것은 lock인데, 모든 객체는 lock을 하나씩 가지고 있다.
    • 객체의 lock을 가지고 있는 쓰레드만 임계 영역의 코드를 수행할 수 있다
  • 여기서는 synchronized 키워드를 이용한 동기화에 대해서만 살펴본다

synchronized

//메서드에 synchronized 키워드 사용
public synchronized void method(){
    ...
}
  • 메서드 전체가 임계영역
  • 메서드에 포함된 객체의 lock을 얻어 작업 수행 후 메서드 종료시 lock 반환
//블럭에 synchronized 키워드 사용
synchronized(lock_얻을_참조변수){
    ...
}
  • 블럭 전체가 임계영역
  • 블럭 영역 안에서 지정한 객체에 대한 lock을 얻고, 블럭을 나가면 lock 반환
  • 메서드 전체에 synchronized 사용하는 것보다 임계 영역 최소화해 성능 최적화 가능

📑 데드락

  • 두 개 이상의 작업이 원하는 자원을 얻지 못해 진행이 멈춘 상태

발생 조건

아래 4가지 조건이 모두 만족하면 교착 상태 발생

  • 상호 배제(Mutual exclusion) : 자원 자체를 동시에 쓸 수 없는 경우
  • 점유 상태로 대기(Hold and wait) : 특정 자원을 점유한 상태로, 다른 자원을 추가로 점유하기 위해 대기하는 경우
  • 선점 불가(No preemption) : 특정 자원을 강제로 빼앗아 사용할 수 없는 경우
  • 순환성 대기(Circular wait) : 자원을 필요로하는 이들이 각각 순환적으로 다른 이들의 자원을 요구하는 경우


    📑📌📜✏️

0개의 댓글