참조 : http://blog.eairship.kr/126(금지된 엑시노아의 비공정 블로그)
스레드란 무엇인가?
"프로그램의 실행 흐름, 프로그램을 구성하고 있는 실행 단위"라 말할 수 있다. 보통 메인 문에서 순차적으로 실행되는 루틴을 많이 다뤄왔는데 이 것은 싱글 스레드이다. 만약에 하나의 프로그램에서 여러 개의 작업을 동시에 수행하고 싶을 경우에는 멀티 쓰레드(Multi Thread)를 사용하면 된다.
스레드를 어떻게 사용하는지?, 어떻게 동작하는지?
(1) Thread 클래스 상속하는 방법
public class ThreadTest { public static class MultiThread extends Thread{ private String name; public MultiThread(String name){ System.out.println(getName() + "스레드가 생성되었습니다."); this.name = name; } @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(getName() + "(" + this.name + ")"); try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { MultiThread mt1 = new MultiThread("Thread1"); MultiThread mt2 = new MultiThread("Thread2"); MultiThread mt3 = new MultiThread("Thread3"); mt1.start(); mt2.start(); mt3.start(); } } | cs |
보통의 싱글 스레드에서 mt1.start(); 코드가 끝나고 mt2.start()코드가 실행되고, 그 다음 mt3.start()가 실행되지만 멀티 스레드에서는 위의 코드들이 동시에 수행됩니다. 그래서 아래의 결과 값처럼 순서에 상관없이 동시에 수행되는 것입니다.
Thread-0스레드가 생성되었습니다. Thread-1스레드가 생성되었습니다. Thread-2스레드가 생성되었습니다. Thread-1(Thread2) Thread-2(Thread3) Thread-0(Thread1) Thread-0(Thread1) Thread-2(Thread3) Thread-1(Thread2) Thread-2(Thread3) Thread-1(Thread2) Thread-0(Thread1) Thread-0(Thread1) Thread-1(Thread2) Thread-2(Thread3) Thread-1(Thread2) Thread-2(Thread3) Thread-0(Thread1) Thread-1(Thread2) Thread-2(Thread3) Thread-0(Thread1) Thread-1(Thread2) Thread-0(Thread1) Thread-2(Thread3) Thread-2(Thread3) Thread-0(Thread1) Thread-1(Thread2) Thread-2(Thread3) Thread-1(Thread2) Thread-0(Thread1) Thread-0(Thread1) Thread-2(Thread3) Thread-1(Thread2) | cs |
Thread State
스레드의 상태는 다음의 형태로 변화됩니다.
Thread.State 값 |
설명 |
NEW |
시작되지 않은 상태 |
RUNNABLE |
실행 가능 상태 |
WAITING |
대기 상태 |
TIMED_WAITING |
스레드가 특정 시간동안 대기 상태 |
BLOCKED |
스레드가 잠겨 있어 풀리기를 기다리는 상태 |
TERMINATED |
스레드가 종료된 상태 |
(2) Runnable Interface를 이용하는 방법
public class ThreadTest { public static class MultiThread implements Runnable{ private String name; public MultiThread(String name){ System.out.println(name + "스레드가 생성되었습니다."); this.name = name; } @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName() + "(" + this.name + ")"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { MultiThread mt1 = new MultiThread("Thread1"); MultiThread mt2 = new MultiThread("Thread2"); MultiThread mt3 = new MultiThread("Thread3"); Thread tr1 = new Thread(mt1); Thread tr2 = new Thread(mt2); Thread tr3 = new Thread(mt3); tr1.start(); tr2.start(); tr3.start(); } } | cs |
Thread의 우선순위
public class ThreadTest { public static class MultiThread implements Runnable{ private String name; public MultiThread(String name){ System.out.println(name + "스레드가 생성되었습니다."); this.name = name; } @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName() + "(우선순위 : " + Thread.currentThread().getPriority() + ")"); } } } public static void main(String[] args) { MultiThread mt1 = new MultiThread("Thread1"); MultiThread mt2 = new MultiThread("Thread2"); MultiThread mt3 = new MultiThread("Thread3"); Thread tr1 = new Thread(mt1); Thread tr2 = new Thread(mt2); Thread tr3 = new Thread(mt3); tr1.setPriority(Thread.MIN_PRIORITY); tr2.setPriority(Thread.NORM_PRIORITY); tr3.setPriority(Thread.MAX_PRIORITY); tr1.start(); tr2.start(); tr3.start(); } } | cs |
쓰레드는 우선 순위에 따라 실행을 우선시 합니다. 물론 출력해보면 꼭 예상되로 되지는 않더라구요.
즉, 우선 순위가 높은 스레드는 우선 순위가 자기보다 낮은 스레드보다 더 많이 실행되는 것입니다.
만약 동일한 우선순위의 스레드가 둘 이상 존재할 경우 CPU의 할당시간을 분배후 실행합니다. 가장 높은 우선 순위는 10,
기본 우선 순위는 5, 가장 낮은 우선 순위는 1로 , 보통 스레드의 우선 순위는 5입니다. 스레드의 우선 순위를 변경하고 싶다면
setPriority()메소드를 사용하면 됩니다. 위의 코드가 그 예제입니다.
Thread의 동기화
public class ThreadTest { public static class clsNumber{ int num = 0; public void addNum(){ num++; } public int getNum(){ return num; } } public static class MultiThread implements Runnable{ clsNumber number; public MultiThread(clsNumber cn){ number = cn; } @Override public void run() { for(int i = 0;i<10000;i++){ number.addNum(); } } } public static void main(String[] args) { clsNumber number = new clsNumber(); MultiThread mt1 = new MultiThread(number); MultiThread mt2 = new MultiThread(number); MultiThread mt3 = new MultiThread(number); Thread tr1 = new Thread(mt1); Thread tr2 = new Thread(mt2); Thread tr3 = new Thread(mt3); tr1.start(); tr2.start(); tr3.start(); try { // join()메소드는 스레드가 끝날 때까지 기다린다. tr1.join(); tr2.join(); tr3.join(); } catch (Exception e) { e.printStackTrace(); } System.out.println(number.getNum()); } } | cs |
결과는??
15380
결과는 30000이 나와야 되는데 15380이 나옵니다. 물론 매번 값도 다르고요. 이유는 무엇일까요?
동기화가 되지 않기 때문에 수행 도중 실행 권한이 다른 스레드로 넘어가서 제대로 된 결과값을 도출해 낼 수 없게 되는 것입니다. 동기화를 해주어야 합니다. 자바에서는 synchronized키워드를 통해 동기화를 가능하게 해줍니다.
동기화를 해준 코드
다음과 같이 synchronized 키워드를 addNum()메소드에 붙여주면 동기화를 지원해주게 됩니다.
public class ThreadTest { public static class clsNumber{ int num = 0; public synchronized void addNum(){ num++; } public int getNum(){ return num; } } public static class MultiThread implements Runnable{ clsNumber number; public MultiThread(clsNumber cn){ number = cn; } @Override public void run() { for(int i = 0;i<10000;i++){ number.addNum(); } } } public static void main(String[] args) { clsNumber number = new clsNumber(); MultiThread mt1 = new MultiThread(number); MultiThread mt2 = new MultiThread(number); MultiThread mt3 = new MultiThread(number); Thread tr1 = new Thread(mt1); Thread tr2 = new Thread(mt2); Thread tr3 = new Thread(mt3); tr1.start(); tr2.start(); tr3.start(); try { // join()메소드는 스레드가 끝날 때까지 기다린다. tr1.join(); tr2.join(); tr3.join(); } catch (Exception e) { e.printStackTrace(); } System.out.println(number.getNum()); } } | cs |
'JAVA' 카테고리의 다른 글
mutable vs immutable (0) | 2015.11.27 |
---|---|
자바 예외 처리 (0) | 2015.11.21 |
GC(Garbage Collection)의 대상은 누구인가? (0) | 2015.11.10 |
LinkedHashMap, TreeMap, HashMap (0) | 2015.11.07 |
Comparable 인터페이스에 대한 이해 (0) | 2015.11.07 |