스레드 구현

자바에서 스레드 구현 방법은 2가지가 있다.
  1. Runnable 인터페이스 구현
    1. Runnable 인터페이스를 구현한 경우는, 해당 클래스를 인스턴스화해서 Thread 생성자에 argument로 넘겨줘야 한다.
  2. Thread 클래스 상속
  • 둘다 run() 메소드를 오버라이딩 하는 방식이다.
  • 자바는 단일 상속 만을 지원하기 때문에 Runnable 인터페이스를 구현하는 것이 많은 이점을 가져갈 수 있다.

스레드 실행

스레드의 실행은 run()이 아닌 start()호출로 해야한다.
  • 분명 run() 메서드를 재정의 했지만 실제 스레드 작업을 시키려면 start()로 작업해야한다.
  • run()으로 작업지시를 하면 스레드를 사용하는 것이 아니게 된다.
  • Java에는 콜 스택이 있다. 이 영역이 실질적인 명령어를 담고 있는 메모리로 , 하나씩 꺼내서 실행시키는 역할을 한다.
    • 만약 동시에 두 가지 작업을 하기 위해선, 두 개 이상의 콜스택이 필요함
    • 스레드를 이용한다는 것은, JVM이 다수의 콜 스택을 번갈아가면 처리를 하는 것이고 사용자에겐 동시에 작업하는 것 처럼 보이게 된다.
    • 즉 run() 메서드를 이용하는 것은 main()의 콜스택에 이용하게 되는 것이고
    • start() 메서드를 호출하면 JVM은 알아서 스레드를 위한 콜 스택을 새로 만들어 주고 새로운 콜스택에 run()을 호출하게 된다.

스레드의 I/O블락킹

  • 입출력시 작업 중단되는 현상
  • 싱글스레드의 경우 I/O을 기다리면서 아무일도 하지 않는다.
  • 멀티스레드의 경우 I/O을 기다리는 것과 동시에 다른 일을 할 수 있다.

스레드의 우선순위

작업의 중요도에 따라 스레드의 우선순위를 다르게 하여 특정 스레드가 더 많은 작업시간을 갖게 할 수 있다.
  • 자바에서는 1~10까지 부여할 수 있고 default를 5이다.
    • setPriority(int newPriority)함수를 통해 변경할 수 있다.
    • 실제로는 참고만 할 뿐 무조건 먼저 실행되지는 않는다.
      • OS 스케줄러가 담당
      • 확률을 높이는 것을 기대함

데몬 스레드

일반 스레드의 작업을 돕는 보조적인 역할을 수행
  • 일반 스레드
  • 데몬 스레드
    • 일반 스레드의 작업을 돕는 보조적인 역할을 수행
    • 일반 스레드가 모두 종료되면 자동으로 종료
    • GC, 자동저장, 화면 자동갱신 등에 사용된다.
    • 무한루프와 조건문을 이용해서 실행 후 대기하다가 특정 조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다.
    void setDaemon(boolean on)
    //스레드를 데몬 스레드로 또는 사용자 스레드로 변경
    //매개변수 on을 true -> 데몬스레드가 된다.
    
    • setDaemon(boolean on)은 반드시 start()를 호출하기 전에 실행되어야 한다. 그렇지 않으면 IllegalTreadStateException이 발생.

스레드 그룹

서로 관련된 스레드를 그룹으로 묶어서 다루기 위한 것
  • 모든 스레드는 반드시 하나의 스레드 그룹에 포함되어 있어야 한다.
  • 지정하지 않고 생성하면 main스레드 그룹에 속한다.
  • 자신을 생성한 스레드의 그룹과 우선순위를 상속받는다.

스레드의 상태

스레드의 상태는 5가지가 있다.
  • NEW
    • 스레드가 생성되고 아직 start()가 호출되지 않은 상태
  • RUNNABLE
    • 실행 중 또는 실행 가능 상태
  • BLOCKED
    • 동기화 블럭에 의해 일시정지된 상태
  • WAITING, TIME_WAITING
    • 실행가능하지 않은 일시정지 상태
  • TERMINATED
    • 스레드 작업이 종료된 상태

https://jongwoon.tistory.com/14

스레드의 실행제어

스레드의 실행을 제어할 수 있는 메서드가 제공된다.

  • static sleep(long m) static sleep(long m, int n)
    • 지정된 시간동안 스레드를 일시정지시킴. 지정된 시간이 지나면 자동으로 실행대기상태가 됨.
    • 특정 스레드를 지정해서 멈추게 하는 것은 불가능하다.
  • void join() void join(long m) void join(long m, int n)
    • 지정된 시간동안 스레드가 실행되도록 한다. 지정된 시간이 지나거나 작업이 종료되면 join()을 호출한 스레드로 다시 돌아와 실행을 계속함.
  • void interrupt()
    • sleep()이나 join()에 의해 일시정지상태인 스레드를 깨워 실행대기 상태로 만든다. 해당 스레드에서는 interrupted exception이 발생함으로써 일시정지 상태를 벗어나게 된다.
  • void stop()
    • 스레드를 즉시 종료시킨다.
  • void suspend()
    • 스레드를 일시정지시킨다. resume()을 호출하면 다시 실행대기상태가 된다.
  • void resume()
    • suspend()에 의해 일시정지상태에 있는 스레드를 실행대기상태로 만든다.
  • static void yield()
    • 실행중에 자신에게 주어진 실행시간을 다른 스레드에게 양보하고 자신은 실행대기상태가 된다.
    • yield, interrupt 메서드를 적절히 사용하면, 응답성과 효율을 높일 수 있다.
  • suspend(), resume(), stop()
    • 이 메서드들은 dead-lock을 발생시키기 쉽기 때문에 사용을 지양하길 권장하고 있다.

스레드의 동기화(synchronization)

멀티 스레드 프로세스에서는 다른 스레드의 작업에 영향을 미칠 수 있다.

  • 진행중인 작업이 다른 스레드에게 간섭받지 않게 하려면 ‘동기화’가 필요
    • 스레드의 동기화 - 한 스레드가 진행중인 작업을 다른 스레드가 간섭하지 못하게 막는 것.
  • 동기화 하려면 간섭받지 않아야 하는 문장들을 ‘임계 영역’으로 설정
    • 임계영역은 lock을 얻은 단 하나의 스레드만 출입가능(객체 1개에 lock 1개)

synchronized를 이용한 동기화

  • synchronized로 임계영역(lock이 걸리는 영역)을 설정하는 방법 2가지
    1. 메서드 전체를 임계영역으로 지정
    public synchronized void calSum(){
    //...
    }
    
    1. 특정한 영역을 임계 영역으로 지정
    synchronized(객체의 참조변수){
    //...
    }
    
  • 임계 영역은 많으면 많을수록 성능이 떨어지기 때문에 최소화 하는 것이 좋다.

wait()와 notify()

동기화를 하면 효율이 떨어진다. 동기화의 효율을 높이기 위해 wait(), notify()를 사용.

  • Object클래스에 정의되어 있으며, 동기화 블록 내에서만 사용할 수 있다.
    • wait()
      • 객체의 lock을 풀고 스레드를 해당 객체의 waiting pool에 넣는다.
    • notify()
      • waiting pool에서 대기중인 쓰레드 중의 하나를 깨운다.
    • notifyAll()
      • waiting pool에서 대기중인 모든 스레드를 깨운다.

'Computer science > JAVA' 카테고리의 다른 글

JVM  (0) 2023.03.16
Instrinsic Lock  (0) 2023.01.08
Casting  (0) 2023.01.01
Object Class  (0) 2023.01.01
String Class  (0) 2023.01.01

+ Recent posts