٩(๑•̀o•́๑)و

20200316 - Thread 본문

Java

20200316 - Thread

11mia 2020. 3. 17. 00:57

Process

  • 실행중인 프로그램 
  • os로부터 메모리를 할당받음 - 프로그램이 메모리에 올라가있는 상태
  • 하나의 프로세스는 하나 이상의 Thread를 가지게 됨

Thread

  • 실제 프로그램이 수행되는 작업의 최소 단위. 작업의 단위
  • 하나의 프로세스는 하나 이상의 Thread를 가지게 됨
  • CPU를 점유하여 돌아가게됨. 스케쥴러가 쓰레드에 CPU를 할당해줌.
  • 두개의 쓰레드가 동시에 돌아가는 것 처럼 보여도 스케쥴러에 의하여 CPU를 점유함.

==> 하나의 프로그램은 반드시 하나 이상의 Thread 상태가 되어서 CPU를 점유.

자바에서 Thread를 구현하는 방법은 크게 두가지.

1. 자바 Thread 클래스로부터 상속받아 구현. (extends Thread)

2. Runnable 인터페이스를 구현. (implements Runnable)

==> 자바는 다중 상속이 허용되지 않으므로 이미 다른 클래스를 상속한 경우 thread를 만들려면 Runnable interface를 implements 해야함.

Thread class 상속
Runnable 구현

Multi-thread 프로그래밍

  • 동시에 여러개의 Thread가 수행되는 프로그래밍
  • Thread는 각각의 작업공간(context)를 가짐 - thread가 스위치되면 context도 스위치됨. - reference 하는 변수 등의 작업 공간 즉 작업환경도 스위칭됨.
  • 공유 자원(shared resource)이 있는 경우 race condition(경쟁)이 발생 -> 서로 공유자원을 가지려함.
  • critical section(임계영역. 공유자원에 대한 영역)에 대한 동기화(synchronization)의 구현이 필요
  • 임계영역에 두개이상의 쓰레드가 동시에 접근할 경우 문제가 생길 수 있음. 따라서 임계영역에 대해서는 순서가 필요함 & 임계영역에는 한번에 딱 한개의 쓰레드만 접근할 수 있음. 임계영역에 락을 걸어두고 이상태에서는 다른 쓰레드는 접근이 불가. => 자바에서는 synchronized 키워드가 제공됨. 이를 이용하여 공유자원에 대한 보호를 하고 동기화를 지원함.

Thread status

  • start되면 Runnable한 상태가 됨. Runnable한 상태에서만 CPU를 점유할 수 있다. 이때 스케쥴러에 의하여 CPU를 할당받음
  • Runnable상태에서 할일이 끝나면 dead상태가됨. (Thread 종료)
  • Thread는 3가지 메서드[sleep(시간), wait(), join()]에 의하여 Runnable 상태에서 Not Runnable 상태로 빠짐. Not Runnable상태에서는 CPU를 점유할 수 없음. 즉, 실행될 수 없음.
  • Not Runnable상태에서 Runnable상태로 돌아오는 방법? - sleep(시간)의 경우엔 시간이 지나면 돌아옴. wait()의 경우에는 notify()나 notifyAll()이 호출되면 돌아옴. join()의 경우에는 다른 쓰레드(쓰레드A)에 join을 건 쓰레드(쓰레드B)가 Not Runnable상태에 있다가 쓰레드A가 종료되면 쓰레드B는 Runnable 상태로 돌아옴
  • Not Runnable상태에서 Runnable상태로 돌아오지 못한 쓰레드들은 InterruptedException을 날려서 인터럽트에 의하여 exception으로 빠짐.

Thread 우선순위

  • Thread.MIN_PRIORITY(=1) ~ Thread.MAX_PRIORITY(=10)
  • 디폴트 우선순위 : Thread.NORM_PRIORITY(=5)
  • setPriority(int newPriority) & int getPriority() : priority를 지정할 수 있고, 얼마인지 얻을 수 있음.
  • 우선순위가 높은 thread는 CPU를 배분받을 확률이 높음

Thread.currentThread()

join() 메서드

  • 다른  thread의 결과를 보고 진행해야 하는 일이 있는 경우 join()메서드를 활용
  • join() 메서드를 호출한 thread가 non-runnable상태가 됨.

interrupt() 메서드

  • 다른 thread에 예외를 발생시키는 interrupt를 보냄 - InterruptedException 발생.
  • thread가 join(), sleep(), wait() 메서드에 의해 blocking되었다면 interrupt에 의해 다시 runnable상태가 될 수 있음.

Thread 종료하기

  • 데몬 등 무한 반복하는 Thread가 종료될 수 있도록 run() 메서드 내의 while문을 활용
  • while문 안에 flag를 사용하여 flag가 true인지 false인지를 이용하여 종료함.
  • Thread.stop()은 사용하지 않음. (Deprecated!)

임계 영역(critical section)

  • 두 개 이상의 thread가 동시에 접근하게 되는 리소스 - shared resource
  • critical section에 동시에 thread가 접근하게 되면 실행결과를 보장할 수 없음
  • thread간의 순서를 맞추는 동기화(synchronization)이 필요
  • 자바에서 주로 공유자원이 되는 것은 static 키워드를 가지는 것

동기화(synchronization)

  • 임계 영역에 여러 thread가 접근하는 경우 한 thread가 수행하는 동안 공유 자원을 lock하여 다른 thread의 접근을 막음
  • 동기화를 잘못 구현하면 deadlock에 빠질 수 있음

자바에서 동기화를 구현하는 방법 역시 크게 2가지 - synchronized  수행문과 synchronized 메서드를 이용

1. synchronized 수행문 (synchronized block방식)

synchronized(참조형 수식){

}
//참조형 수식에 해당되는 객체에 lock을 건다.

2. synchronized 메서드

  • 메서드 선언부에 synchronized 키워드 사용
  • 현재 이 메서드가 속해있는 객체에 lock을 건다
  • synchronized 메서드 내에서 다른 synchronized 메서드를 호출하지 않는다. (deadlock 방지 위함)
  • run() 자체를 synchronized 메서드로 만드는 것은 의미가 없음 - 이 경우에는 쓰레드 자체에 락이 걸리기때문.

동기화 하지 않았을 경우 - minusMoney가 무시됨
synchronized 메서드를 이용한 동기화 구현
synchronized 선언문(block) 을 이용한 동기화
thread에서 synchronized 선언문 방식 사용

wait() / notify()

  • wait() : 리소스는 한정적임. 리소스가 더 이상 유효하지 않은 경우 리소스가 사용 가능할 때 까지 thread를 non-runnable 상태로 전환. wait() 상태가 된 thread는 notify()가 호출될 때 까지 기다린다.
  • notify() : wait()하고 있는 thread중 한 thread를 runnable 한 상태로 깨움. 하나를 깨우는데 무작위로 하나를 깨움. 따라서 계속 못깨어나는 쓰레드가 있을 수 있음. Object class의 메서드.
  • notifyAll() : wait()하고 있는 모든 thread가 runnable 한 상태가 되도록 함. notify()보다 notifyAll()을 사용하기를 권장. 특정 thread가 통지를 받도록 제어할 수 없으므로 모두 깨운 후 scheduler에 의해 CPU를 점유하는 것이 좀 더 공평하다고함. Object class의 메서드.