티스토리 뷰

Java

10. 멀티쓰레드 프로그래밍

kingsubin 2021. 1. 27. 14:38

목표

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

학습할 것 (필수)

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

Thread 클래스와 Runnable 인터페이스

Java 에서 쓰레드를 생성하는 방법에는 Thread 클래스 상속받기, Runnable 인터페이스 구현하기 2가지 방법이 있다.

Thread 클래스는 Runnable 인터페이스를 구현한 클래스이므로 그냥 어떤 것을 적용하느냐의 차이이다.

 

어떤 것을 사용할까 ?

- 다중 상속을 지원하지 않으므로 확장할 필요가 있을 경우에는 Runnable 인터페이스를 구현, 그렇지 않은 경우는 Thread 클래스를 사용한다.

 

Thread 는 순서대로 동작하는가 ?

- 순서대로 실행되지 않는다.

- 컴퓨터의 성능에 따라 달라 질 수도 있으면 매번 결과가 다르다.

public class ThreadSample extends Thread {
  public void run() {}
}

public class RunnableSample implements Runnable {
  public void run() {}
}

class Test {
  public static void main(String[] args) {
    ThreadSample threadSample = new ThreadSample();
    Thread runnableSample = new Thread(new RunnableSample);
  }
}

스레드의 상태

Thread 의 실행시점은 .start() 메소드로 실행되는 것 처럼 보이지만 실제로는 그렇지 않고 실행 대기 상태가 되고 스케쥴러가 실행시키는 방식이다.

https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Thread.State.html
https://sujl95.tistory.com/63#comment16797156


스레드의 우선순위

https://catch-me-java.tistory.com/47

1. 우선순위를 이용한 방법

- 우선순위가 높은 스레드가 더 많은 작업을 할 수 있도록 설정하는 것

- 스레드가 가질 수 있는 우선순위 범위는 1~10까지 이며, 숫자가 높을 수록 우선순위 또한 높아진다.

 

스레드 클래스의 필드를 보면 우선순위 값이 명시되어 있다.

static int MAX_PRIORITY = 10

static int MIN_PRIORITY = 1

static int NORM_PRIORITY = 5

class TestThread extends Thread {
  public void run() {
    for (int i = 0; i < 3; i++) {
      System.out.println(Thread.currentThread().getName());

      try {
          Thread.sleep(10);
      } catch (InterruptedException e) {
          e.printStackTrace(); 
      }
    }
  }
}

class Test {
  public static void main(String[] args) {
    TestThread thread1 = new Thread();
    TestThread thread2 = new Thread();
    thread1.setPriority(10);
    thread1.start(); // Thread-0
    thread2.start(); // Thread-1
  }
}

/*
Thread-1
Thread-0
Thread-1
Thread-0
Thread-1
Thread-0
*/

 

2. 순환 할당을 이용한 방법

- 각자 시간 할당량을 정해서 하나의 스레드가 정해진 시간만큼만 실행하고 다시 다른 스레드를 실행하는 것

- 이런 방식은 JVM 이 정하기 때문에 코드로 제어할 수 없다.


Main 스레드

public static void main(String[] args) { }

-메인 스레드는 main 메소드를 통해서 실행하게 된다.

-다른 스레드를 실행하지 않고 main 메소드만 존재하는 것을 싱글 스레드 어플리케이션이라고 하며,

  메인 스레드가 종료 되면 프로세스 자체도 종료된다.

 

멀티 스레드 애플리케이션

- 메인 쓰레드에서 스레드를 생성하여 실행하는 것을 멀티 스레드 애플리케이션이라고 한다.

https://eun-jeong.tistory.com/20

데몬 스레드

- 메인 스레드를 보조하는 스레드

- 보조 역할이기 때문에, 메인스레드 종료시 데몬 스레드 강제 종료됨

 

데몬 스레드 지정 하는법

- main 스레드가 Daemon이 될 쓰레드의 setDaemon(true) 를 호출하면 Daemon 스레드가 된다.

public class DaemonThread extends Thread {
  public void run() {
    System.out.println("hello");
  }
}

public class Test {
  public static void main(String[] args) {
    DaemonThread daemon = new DaemonThread();
    daemon.setDaemon(true);
  }
}

동기화 (Synchronize)

- 싱글 스레드 애플리케이션에서는 상관이 없지만 멀티 스레드 상황이라면 여러개의 스레드가 한 객체를 변경할 수도 있다.

- 여러 개의 스레드가 한 개의 리소스를 사용하려고 할 때 사용하려는 쓰레드를 제외한 나머지의 접근을 막는 것을

쓰레드에 안전하다고 한다. (Thread-safe)

 

Synchronized 키워드를 사용하여 동기화 하는 방법

- 메소드 자체를 synchronized 로 선언하는 방법 (synchronized methods)

- 메소드 내의 특정 문장만 synchronized 로 감싸는 방법 (synchronized statements)

public synchronized void method() {
  // 단 하나의 스레드만 실행
}

public void method2() {
  // 다른 스레드도 접근 가능
}
public void method() {
  synchronized() {
   // 단 하나의 스레드만 실행
  }

  // 다른 스레드도 접근 가능
}

데드락

- 둘 이상의 스레드가 자원을 획득하기 위해 대기하는데, 이 자원을 점유하고 있는 스레드도 똑같이 다른 자원을 기다리면서 서로 block 상태에 놓이는 것을 말한다.

- 데드락은 다수의 스레드가 같은 lock 을 동시에, 다른 명령에 의해 획득하려 할 때 발생할 수 있다.


잘 정리된 블로그 게시글들이 있어서 여러 번 읽어보았다.

자세한 내용은 아래 블로그 게시글을 보는게 더 도움이 될 것 같다.

 

※ 참조

catch-me-java.tistory.com/47

sujl95.tistory.com/63#comment16797156

※ 스터디

github.com/whiteship/live-study/issues/10

'Java' 카테고리의 다른 글

12. 애노테이션  (0) 2021.02.06
11. Enum  (0) 2021.01.29
9. 예외처리  (0) 2021.01.17
8. 인터페이스  (0) 2021.01.09
7. 패키지  (0) 2021.01.02