[JAVA 35] 자바 쓰레드 ( Thread )
■ Thread ( 쓰레드 )
1. 프로세스를 구성하는 ' 제어의 흐름 ' 이다.
2. Process 와 Thread
- Process : 프로그램의 실행 단위
- Thread : Process 를 구성하는 작업 단위
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class ThreadS1 extends Thread{ // Thread Study 1 ThreadS1(){ start(); while(true){ try{ Thread.sleep(1000); // 1초 잠들어 있다가 실행을 반복 ( msec ) }catch(InterruptedException ie){ System.out.println("생성자() 예외"); } System.out.println("행동1"); } } public void run(){ // run(); 메소드는 4번째 줄에 있는 start(); 가 호출한다. while(true){ try{ Thread.sleep(500); // 0.5초 잠들어 있다가 실행을 반복 ( msec ) }catch(InterruptedException ie){ System.out.println("쓰레드 메소드() 예외"); } System.out.println("행동2"); } } public static void main(String[] args){ new ThreadS1(); } } | cs |
3.. 특징
쓰레드는 프로세스 와 ' 공통 Resource ' 를 서로 공유하기 때문에
' 경량 프로세스 ' 라고 불릴 정도로 가볍다.
4. 생성 방법
1) java.lang.Thread 를 상속받는 방법 ~ extends Thread
2) java.lang.Runnable 을 구현하는 방법 ~ implements Runnable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | class Thread1 extends Thread{ public void run(){ while(true){ try{ Thread.sleep(1000); }catch(InterruptedException ie){ System.out.println("Thread1 예외"); } System.out.println("행동 1"); } } } class Thread2 implements Runnable{ public void run(){ while(true){ try{ Thread.sleep(1000); }catch(InterruptedException ie){ System.out.println("Thread2 예외"); } System.out.println("행동 2"); } } } class User2{ User2(){ Thread th1 = new Thread1(); th1.start(); // JVM → 제어 → run() Runnable r = new Thread2(); Thread th2 = new Thread(r); th2.start(); while(true){ try{ Thread.sleep(1000); }catch(InterruptedException ie){ System.out.println("User2 생성자 예외"); } System.out.println("행동 3"); } } public static void main(String[] args){ new User2(); } } | cs |
5. 시작 메소드
쓰레드객체.start();
6. ex1) 인터넷에서 음악을 들으면서 그 음악을 다운로드
6. ex2) 게임을 플레이 하면서 대화를 함과 동시에 배경음악이 나온다.
6. ex3) 문자 입력과 동시에 오타처리
6. ex4) 메신저에서 파일을 다운로드 중에 채팅 가능
등등
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | class Action1 extends Thread{ public void run(){ action1(); } private void action1(){ while(true){ try{ Thread.sleep(1500); }catch(InterruptedException ie){} System.out.println("행동 1"); } } } class Action2 extends Thread{ public void run(){ action2(); } private void action2(){ while(true){ try{ Thread.sleep(1000); }catch(InterruptedException ie){} System.out.println("행동 2"); } } } class User3{ User3(){ new Action1().start(); new Action2().start(); action3(); } void action3(){ while(true){ try{ Thread.sleep(2000); }catch(InterruptedException ie){} System.out.println("행동 3"); } } public static void main(String[] args){ new User3(); } } | cs |
7. Priority
1) Ready 상태의 쓰레드 중에서 , 우선적으로 CPU를 점유할 수 있는 쓰레드를 판별하기 위한 LEVEL 값
2) 범위
1 ~ 10
숫자가 클수록 우선순위가 높아진다.
3) 상수
MAX_PRIORITY
MIN_PRIORITY
NORM_PRIORITY
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class YieldS1 extends Thread{ // yield study 1 public void run(){ for(int a=0 ; a < 1000 ; a++){ System.out.println("a : " + a); yield(); } } } class ThreadS4 extends Thread{ Thread th1; Thread th2; ThreadS4(){ int max = Thread.MAX_PRIORITY; int min = Thread.MIN_PRIORITY; int norm = Thread.NORM_PRIORITY; System.out.println("max : " + max); System.out.println("min : " + min); System.out.println("norm : " + norm); } public static void main(String[] args){ new ThreadS4(); } } | cs |
8. LifeCycle
1) 5가지의 상태로 구성되어 있다.
2) 상태이동은 메소드나 스케쥴러에 의해 가능하다.
3) ' 소멸상태 ' run()의 {}이 수행되면 자동으로 이동된다.
( 단, 메인쓰레드는 main()의 {}가 수행되면 이동이 된다. )
cf1) wait() , notify() , notifyAll() 메소드는 항상 synchronized 블럭 내에서 사용되어야 한다.
cf2) wait() , sleep() 사용시에는 InterruptedException 예외를 처리해야 한다.
9. 주요메소드
1) sleep(시간) : 해당 시간동안만 waiting 상태에 존재한다.
2) yield() .: running 상태의 쓰레드가 양보하게 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | class YieldS1 extends Thread{ // yield study 1 public void run(){ for(int a=0 ; a < 100 ; a++){ System.out.println("a : " + a); yield(); } } } class ThreadS4 extends Thread{ Thread th1; Thread th2; ThreadS4(){ th1 = new YieldS1(); th1.setPriority(Thread.MIN_PRIORITY); th1.yield(); th1.start(); th2 = this; th2.setPriority(Thread.MAX_PRIORITY); th2.start(); } void showP(){ // show priority int pt = this.getPriority(); // b 의 행동을 우선순위를 높게 준다. System.out.println("pt : " + pt); } public void run(){ for(int b=0 ; b<100 ; b++){ System.out.println("b : " + b); yield(); } } public static void main(String[] args){ ThreadS4 ts4 = new ThreadS4(); ts4.showP(); } } | cs |
3) join() .: 자식 쓰레드에 적용하게 되면 부모 쓰레드는 자식이 죽을 때 까지 기다리게 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | class TS1 extends Thread{ // Thread Study 1 public void run(){ try{ Thread.sleep(5000); // 5초 뒤에 끝 }catch(InterruptedException ie){} System.out.println("쓰레드 1 끝"); } } class TS2 implements Runnable{ // Thread Study 2 public void run(){ Thread th = new TS1(); th.start(); try{ Thread.sleep(3000); // 3초 뒤에 끝 th.join(); }catch(InterruptedException ie){} System.out.println("쓰레드 2 끝"); } } class TS3{ Thread th; TS3(){ th = new Thread(new TS2()); th.start(); try{ th.join(); }catch(InterruptedException ie){} } public static void main(String[] args){ new TS3(); System.out.println("메인 쓰레드 끝"); } } | cs |
TS2 는 3초 뒤에 끝나고 TS1 은 5초뒤에 끝나기 때문에
"쓰레드 2 끝"이 "쓰레드 1 끝"보다 2초 빠르게 출력이 되어야 한다.
하지만 join(); 으로 인해서 "쓰레드 1 끝"을 기다리고 함께 끝이 나게 된다.
10. 쓰레드 동기화
1) 하나 이상의 쓰레드가 어떤 연산에 동시에 접근했을 때
그 연산에 대한 값의 무결성을 보장하기 위해서 수행 영역에 대한 LOCK을 걸어 주는 것
ex1) 화장실의 문고리
ex2) static int i = 0;
i++;
# CPU 연산 단계 # A B
(1) 현재의 i 값을 읽는 단계 i==0 i==0 ( 무결성이 깨진다. )
(2) i 값을 증가시키는 단계 i==0 i==0
(3) 증가된 i 값을 i 에 저장하는 단계 i==1 i==1
2) a. synchronized void m1(){ 연산 }
b. void m2(){
{synchronized(this){
연산
}}
}
synchronized 로 감싸진 영역을 동기화 블록이라고 한다.
동기화 블록 내에서는 오직 하나의 쓰레드만이 동시에 작업을 수행할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class ThreadS5 extends Thread{ // Thread Study 5 static int a; ThreadS5(){ start(); } public void run(){ m1(); m2(); } synchronized void m1(){ a++; System.out.println("a : " + a); } void m2(){ int b = 0; b--; {synchronized(this){ a++; }} System.out.println("b : " + b); } public static void main(String[] args){ new ThreadS5(); } } | cs |