스레드란? 스레드의상태 스레드스케줄링 동기화 스레드그룹 kkman@sangji.ac.kr 2
시작, 실행, 종료의순서를가지는제어흐름단위 단일스레딩시스템 : 오직하나의실행점 멀티스레딩시스템 : 다중의실행점 kkman@sangji.ac.kr 3
Concurrent Programming Multiprogramming System Multiprocessing System Multithreading System 프로세스에비해문맥전환 (context switching) 에대한오버헤드를줄일수있다. 공유힙, 공유데이터, 코드를공유 동일주소공간 kkman@sangji.ac.kr 4
스레드도하나의객체로처리. 스레드객체의생성 Thread worker = new Thread(); 스레드시작 worker.start(); 스레드생성순서 스레드클래스정의 => 스레드객체생성 => 스레드시작 스레드클래스의정의 방법 2 가지 : Thread 클래스확장, Runnable 인터페이스구현 스레드동작기술 : public void run() 메소드를재정의 kkman@sangji.ac.kr 5
Thread 클래스를확장하여구현 확장된클래스를위한 run 메소드를작성 class SimpleThread extends Thread { public void run() { // 스레드객체생성 SimpleThread t = new SimpleThread() ; 스레드시작 t.start() ; kkman@sangji.ac.kr 6
객체의생성과동시에시작 new SimpleThread().start(); run 메소드 스레드실행의시작장소 순차프로그램의 main() 과동일 run 메소드가종료되면스레드종료 kkman@sangji.ac.kr 7
Thread 클래스확장을통한스레드클래스구현예 [ 예제 11.1 - SimpleThreadTest.java] class SimpleThread extends Thread { public SimpleThread(String i name) { super(name); public void run() { System.out.println(getName() + " is now running."); public class SimpleThreadTest { public static void main(string[] args) { SimpleThread t = new SimpleThread("SimpleThread"); System.out.println("Here : 1"); t.start(); System.out.println("Here : 2"); 실행결과 : Here : 1 SimpleThread is now running. Here : 2 kkman@sangji.ac.kr 8
Runnable 인터페이스를구현하여스레드클래스를정의 public interface Runnable { public abstract void run(); Runnable 인터페이스구현예 : class SimpleThread implements Runnable { public void run() { //... //... Thread t1 = new Thread(new SimpleThread()); kkman@sangji.ac.kr 9
Runnable 인터페이스구현을통한스레드클래스구현 [ 예제 11.2 - ImplOfRunnable.java] class RunnableThread implements Runnable { public void run() { System.out.println("Implementation of Runnable"); public class ImplOfRunnable { public static void main(string[] args) { Thread t = new Thread (new RunnableThread()); System.out.println("Here : 1"); t.start(); System.out.println( println("here : 2"); 실행결과 : Here : 1 Here : 2 Implementation of Runnable kkman@sangji.ac.kr 10
스레드상태전이도와관련메소드 kkman@sangji.ac.kr 11
New Thread 상태 스레드객체만을생성한상태 Thread mythread = new SimpleThread(); 어떤시스템자원도할당받지않은상태 start 메소드만가능 Runnable 상태 실행가능한상태, 스케줄링을받을수있는상태. mythread.start(); start() 메소드 1. 필요한시스템자원을할당하고 2. 스레드를스케줄링한후, 3. 스레드객체의 run() 메소드를호출한다. kkman@sangji.ac.kr 12
Runnable 상태 Not Runnable 상태 sleep() 를호출 wait() 를호출 입출력을위해블록되었을때 Not Runnable 상태 Runnable 상태 sleep() : 지정된시간경과 wait() : 다른메소드에의해 notify(), notifyall() 입출력 : 해당입출력의완료 suspend(), resume() 지원안함 kkman@sangji.ac.kr 13
Dead 상태 run 메소드의종료 isalive() public void run() { int i = 0; while ( i < 100) { i++; System.out.println("i i ="+i ); true: Runnable이거나 Not Runnable 상태 false: New Thread이거나 Dead 상태 kkman@sangji.ac.kr 14
Runnable 상태에있는여러스레드의실행순서를제어 고정우선순위 (Fixed Priority) 스케줄링알고리즘 상대적우선순위에기반을두고스레드의실행순서를결정 높은우선순위를갖는스레드에게실행의권한 스레드우선순위 MIN_PRIORITY, MAX_PRIORITY 값이클수록높은우선순위 디폴트우선순위 : NORM_PRIORITY kkman@sangji.ac.kr 15
선택된스레드는다음조건중에하나가참이될때까지실행 더높은우선순위의스레드가실행가능하게될경우 선택된스레드가양보하거나, 그의 run 메소드가종료된경우 시분할 (time sharing) 시스템에서, 스레드에할당된시간이만료된경우 선점적 (preemptive) 다른 Runnable 스레드보다더높은우선순위를갖는스레드가 Runnable 하게되면, 자바시스템은새로운더높은우선순위의 스레드가실행되도록선택 kkman@sangji.ac.kr 16
스레드를생성시킨스레드의우선순위상속 스레드우선순위관련메소드 public final void setpriority(int newpriority) : 스레드의우선순위를변경한다. public final int getpriority() : 현재스레드의우선순위를반환한다. 지속적인작업을행하는스레드의우선순위는 MIN_PRIORITY 로설정이바람직 긴급한작업을즉각적으로처리 kkman@sangji.ac.kr 17
스케줄링제어메소드 public static void sleep(long millis) public static void sleep(long millis, int nanos) public static void yield() 예제 public void run() { for (int i=0; i < howoften; i++) { System.out.println(word); if (doyield) yield(); kkman@sangji.ac.kr 18
[ 예제 11.4 - SchedulerTest.java] class RunThread extends Thread { public RunThread(String name) { super(name); public void run() { for(int i = 1; i <= 200000; i++) { if (i % 50000 == 0) System.out.println("Thread [" + getname() + "] is activated => " + i); public class SchedulerTest { private final static int NUM = 2; public static void main(string[] args) { Thread[] p = new RunThread[NUM]; p[0] = new RunThread("Pear "); p[1] = new RunThread("Apple"); p[0].start(); p[1].start(); kkman@sangji.ac.kr 19
예제 11.4 결과 1 시분할을지원하는시스템의실행결과 Thread [Pear ] is activated t => 50000 Thread [Apple] is activated => 50000 Thread [Pear ] is activated => 100000 Thread [Pear ] is activated => 150000 Thread [Apple] is activated => 100000 Thread [Apple] is activated => 150000 Thread [Pear ] is activated => 200000 Thread [Apple] is activated => 200000 kkman@sangji.ac.kr 20
예제 11.4 결과 2 시분할을지원하지않는시스템실행결과 Thread [Pear ] is activated t => 50000 Thread [Pear ] is activated => 100000 Thread [Pear ] is activated => 150000 Thread [Pear ] is activated => 200000 Thread [Apple] is activated => 50000 Thread [Apple] is activated => 100000 Thread [Apple] is activated => 150000 Thread [Apple] is activated => 200000 kkman@sangji.ac.kr 21
여러스레드의중첩실행을방지 직원 1 \1,000,000 직원 2 \1,000,000 \100,000 입금 \1,100,000 계좌 A에서잔액조회총액계산계좌 A 에서총액기록 계좌 A 에서잔액조회 총액계산 계좌 A 에서총액기록 \200,000 입금 \1,200,000 000 시간 kkman@sangji.ac.kr 22
메소드단위로 --- 동기화메소드 객체를 Lock synchronized method 클래스단위로 --- 동기화정적메소드 synchronized static method 문장단위로 --- 동기화문장 synchronized statement kkman@sangji.ac.kr 23
동일한객체에대하여여러스레드의중첩실행을방지할때사용 객체의락 (lock) kkman@sangji.ac.kr 24
연산의순서는보장되지않음 class Account { private double balance; public Account(double initialdeposit) { balance = initialdeposit; public synchronized double getbalance() { // 잔액조회 return balance; public synchronized void deposit(double amount) { // 총액계산및기록 balance += amount; kkman@sangji.ac.kr 25
클래스단위로동기화 동시에같은클래스에속한동기화정적메소드를실행할수없음클래스단위의락 (lock) 은객체에영향없음 동기화메소드재정의 동기화속성은상속되지않음 kkman@sangji.ac.kr 26
문장단위로동기화 동기화메소드는메소드전체에대한락 (lock) 을갖기때문에병렬성이저하 문장형태 synchronized (expr) < 문장 > Lock 하고자하는객체 /* 배열내의모든원소를양수로만든다. */ public static void abs(int[] values) { synchronized (values) { for(int i = 0; i < values.length; i++) { if (value[i] < 0) values[i] = -values[i]; kkman@sangji.ac.kr 27
멀티스레드환경을고려하지않은메소드의처리 class ExistingClass { //... void method() { //... class ExtendedClass extends ExistingClass { //... synchronized void method() { super.method(); 마치슈퍼클래스에있는메소드가동기화메소드인것처럼동작 kkman@sangji.ac.kr 28
스레드간의통신이필요할때사용 wait() 어떤조건의변화가있을대까지기다리는메소드 notify() 어떤조건이변경되었다는사실을대기중인스레드에게통지하는메소드 kkman@sangji.ac.kr 29
wait 메소드가사용가능한위치 동기화메소드내동기화문장내동기화정적메소드내 synchronized void dowhencondition() { while (!condition) wait(); // Do what needs doing when the condition is true Not Runnable 상태로전이되고 notify( 또는, notifyall) 메시지를받을때까지기다린다. kkman@sangji.ac.kr 30
대기중인스레드의실행을재개 synchronized void changecondition() { // change some value used in a condition test notify(); notifyall() 여러스레드가같은객체의모니터에서기다리는경우모든대기스레드를깨움 kkman@sangji.ac.kr 31
환형큐 - head 에삽입, tail 에서제거 kkman@sangji.ac.kr 32
get 메소드 public synchronized int get() { int value; while (count == 0) try { wait(); catch (InterruptedException e) { value = contents[tail]; tail = (tail + 1) % size; count--; notifyall(); return value; kkman@sangji.ac.kr 33
put 메소드 public synchronized void put(int value) { while ( count == size ) try { wait(); catch (InterruptedException t ti e) contents[head] = value; head = (head + 1) % size; count++; notifyall(); kkman@sangji.ac.kr 34
병행프로그램의대표적인예 생산자 (producer) 자료의스트림을생성하여버퍼에삽입 소비자 (consumer) 버퍼로부터자료를제거하여소비 kkman@sangji.ac.kr 35
고려사항 소비자는버퍼가비어있으면블록 생산자는버퍼가가득차있으면블록 생산자와소비자는버퍼의용량이허락하는한독립적으로실행 생산자와소비자는동일시점에버퍼의내용을갱신해서는안됨 다수의생산자와소비자가존재하는경우를대비 kkman@sangji.ac.kr 36
Producer 클래스 class Producer extends Thread { private CircularQueue boundedbuffer; private int number; public Producer(CircularQueue c, int number) { super("producer #" + number); boundedbuffer = c; this.number = number; public void run() { for (int i = 0; i < 10; i++) { boundedbuffer.put(i); db System.out.println(getName() + " put: " + i); try { sleep((int)(math.random() () * 100)); catch (InterruptedException e) { kkman@sangji.ac.kr 37
Consumer 클래스 class Consumer extends Thread { private CircularQueue boundedbuffer; private int number; public Consumer(CircularQueue c, int number) { super("consumer #" + number); boundedbuffer = c; this.number = number; public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = boundedbuffer.get(); System.out.println(getName() + " got: " + value); kkman@sangji.ac.kr 38
테스트클래스 public class ProducerConsumerTest { public static void main(string[] args) { CircularQueue c = new CircularQueue(1); // 버퍼의크기는 1로한정 Producer p1 = new Producer(c, 1); Consumer c1 = new Consumer(c, 1); p1.start(); c1.start(); Producer #1 put : 0 결과 Consumer #1 got : 0 Producer #1 put : 1 Consumer #1 got : 1..... kkman@sangji.ac.kr 39
자원을가지고있는스레드와자원을요구하는스레드들상호간에환형의존으로인하여더이상의처리가불가능한상태 kkman@sangji.ac.kr 40
식사하는철학자문제 데드락의해결 데드락예방과탐지 (prevention and detection) kkman@sangji.ac.kr 41
스레드그룹 모든스레드는스레드그룹의일원 여러개의스레드를하나의객체로관리하는방법제공한번에여러개의스레드를다룰수있는방법제공 스레드그룹의생성 ThreadGroup mythreadgroup = new ThreadGroup( ThreadGroupName ); ThreadGroup mythreadgroup = new ThreadGroup(ThreadGroupParent, "ThreadGroupName"); 그룹안의스레드객체생성 Thread mythread = new Thread(myThreadGroup, "a thread for my group"); kkman@sangji.ac.kr 42
특정스레드그룹에속하는스레드생성 public Thread(ThreadGroup group, Runnable target) public Thread(ThreadGroup group, String name) public Thread(ThreadGroup group, Runnable target, String name) 자신이속한스레드그룹확인 mygroup = mythread.getthreadgroup(); kkman@sangji.ac.kr 43
스레드그룹계층구조 system 스레드그룹 (garbage collector,...) main 스레드그룹 (main 스레드 ) mythreadgroup1 (mythread1_1,...)... mythreadgroupn (mythreadn_1,...) kkman@sangji.ac.kr 44