Thread란?
- 하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업 단위
- 운영체제에 의해 관리되는 하나의 작업(Task)
- Thread = Task(작업)
- JVM에 의해 하나의 프로세스가 발생하고 main() 안의 실행문들이 하나의 스레드
- main() 이외의 또 다른 스레드를 만들려면 Thread 클래스를 상속하거나 Runnable 인터페이스 구현
- 멀티 스레드 작업 시, 각 스레드끼리 정보를 주고받을 수 있어 처리 과정의 오류를 줄일 수 있음
- 프로세스끼리는 정보 교환 불가능
멀티 스레드(Multi Thread)란?
여러 스레드를 동시에 실행시키는 응용프로그램을 작성하는 기법
장점
- 메모리 공유로 인한 시스템 자원 소모 줄어듬
- 동시 작업이 가능
단점
- 자원을 공유하기에 충돌 발생 가능성 존재
- 로직의 복잡도가 증가하여 버그 생성확률 증가
Thread 생명주기
1. Runnable (준비상태)
- 스레드가 실행되기 위한 준비 단계
- CPU를 점유하고 있지 않으며 실행(Running)을 하기 위한 대기 상태
- start() 메소드 호출 시 run() 메소드에 설정된 스레드가 Runnable 상태로 진입
- "Ready" 상태
2. Running (실행상태)
- CPU를 점유하여 실행하고 있는 상태
- JVM에 의해 run() 호출
- Runnable 상태의 여러 스레드 중 우선 순위를 가진 스레드를 JVM이 run() 호출로 해당 스레드 Running 상태로 진입
3. Dead (종료상태)
- Running 상태의 스레드가 모두 실행되고 난 후 완료 상태
- "Done" 상태
4. Blocked (지연상태)
- CPU 점유권을 상실한 상태
- 후에 특정 메소드 호출로 Runnable (준비상태)로 상태 전환
- wait() 메소드로 Blocked 상태가 된 스레드는 notify() 메소드 호출로 인해 Runnable (준비상태)로 상태 전환
- sleep(시간) 메소드에 의해 Blocked 상태가 된 스레드는 지정된 시간 지난 후 Runnable (준비상태)로 상태 전환
Thread 예제
1. Single Thread (Thread 클래스 상속)
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 | package com.example.demo; public class SingleThreadEx extends Thread{ private int[] temp; public SingleThreadEx(String threadname){ super(threadname); temp = new int[10]; for (int start = 0; start < temp.length; start++ ){ temp[start] = start; } } public void run(){ // Runnable -> Running for(int start:temp){ try{ Thread.sleep(1000); // Running -> Blocked (1초마다 호출) }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("스레드 이름 : " + currentThread().getName()); System.out.println("temp value : " + start); } } public static void main(String[] args){ SingleThreadEx st = new SingleThreadEx("첫 번째"); // new st.start(); // new -> Runnable } } | cs |
스레드 이름 : 첫 번째
temp value : 0
스레드 이름 : 첫 번째
temp value : 1
스레드 이름 : 첫 번째
temp value : 2
....
스레드 이름 : 첫 번째
temp value : 9
2. Single Thread (Runnable 인터페이스 상속) : 1 방법보다 많이 쓰임
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 | package com.example.demo; public class SingleThreadEx2 implements Runnable{ private int[] temp; public SingleThreadEx2(){ temp = new int[10]; for (int start = 0; start < temp.length; start++ ){ temp[start] = start; } } @Override public void run(){ for(int start:temp){ try{ Thread.sleep(1000); // Running -> Blocked (1초마다 호출) }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("스레드 이름 : " + Thread.currentThread().getName()); System.out.println("temp value : " + start); } } public static void main(String[] args){ SingleThreadEx2 st = new SingleThreadEx2(); Thread t = new Thread(st, "첫번째"); t.start(); } } | cs |
스레드 이름 : 첫 번째
temp value : 0
스레드 이름 : 첫 번째
temp value : 1
스레드 이름 : 첫 번째
temp value : 2
....
스레드 이름 : 첫 번째
temp value : 9
3. Multi Thread
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package com.example.demo; public class Main { public static void main(String[] args) { ThreadEx threadEx1 = new ThreadEx(); ThreadEx threadEx2 = new ThreadEx(); Thread thread1 = new Thread(threadEx1, "A"); Thread thread2 = new Thread(threadEx2, "B"); // 동기로 thread1 끝나고 thread2 실행 thread1.start(); thread2.start(); } } | cs |
Thread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.example.demo; import org.aspectj.weaver.ast.Test; public class ThreadEx implements Runnable{ int TestNum = 0; @Override public void run() { // 스레드가 수행할 로직 for(int i=0; i<10; i++){ if(Thread.currentThread().getName().equals("A")){ System.out.println("==================="); TestNum++; } System.out.println("ThreadName = " + Thread.currentThread().getName() + " TestNum = " + TestNum); } } } | cs |
===================
ThreadName = A TestNum = 1
===================
ThreadName = A TestNum = 2
===================
ThreadName = A TestNum = 3
===================
ThreadName = A TestNum = 4
===================
ThreadName = A TestNum = 5
===================
ThreadName = A TestNum = 6
===================
ThreadName = A TestNum = 7
===================
ThreadName = A TestNum = 8
===================
ThreadName = A TestNum = 9
===================
ThreadName = A TestNum = 10
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
4. Multi Thread 예제 : 동기화
ATM.java
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 | package com.example.demo; import lombok.Synchronized; public class ATM implements Runnable{ private long depositeMoney = 10000; @Override public void run() { synchronized (this) { for (int i = 0; i < 10; i++) { notify(); // Blocked -> Runnable try { wait(); // Running -> Blocked Thread.sleep(1000); // 1초마다 호출 } catch (InterruptedException e) { e.printStackTrace(); } if (getDepositeMoney() <= 0) break; withDraw(1000); } } } public void withDraw(long howMuch){ if(getDepositeMoney() > 0){ depositeMoney -= howMuch; System.out.print(Thread.currentThread().getName() + " , "); System.out.printf("잔액 : %,d 원 %n", getDepositeMoney() ); } else{ System.out.print(Thread.currentThread().getName() + " , "); System.out.println("잔액이 부족합니다."); } } public long getDepositeMoney(){ return depositeMoney; } } | cs |
Synchronized.java
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.example.demo; public class SynchronizedEx { public static void main(String[] args) { ATM atm = new ATM(); Thread mother = new Thread(atm, "mother"); Thread son = new Thread(atm, "son"); mother.start(); // new -> Runnable son.start(); } } | cs |
mother , 잔액 : 9,000 원
son , 잔액 : 8,000 원
mother , 잔액 : 7,000 원
son , 잔액 : 6,000 원
mother , 잔액 : 5,000 원
son , 잔액 : 4,000 원
mother , 잔액 : 3,000 원
son , 잔액 : 2,000 원
mother , 잔액 : 1,000 원
son , 잔액 : 0 원
반응형
'Computer Language > JAVA' 카테고리의 다른 글
[JAVA] Map 전체 출력(entrySet, keySet, Iterator) (0) | 2022.09.27 |
---|