티스토리 뷰
728x90
반응형
Thread란?
- 스레드란 한 프로세스에서 동작되는 여러 흐름입니다. 쉽게 말하자면 크롬에서 여러개의 탭을 사용중에 있거나 교통체증을 막기위하여 여러개의 차선이 있는것이라고 생각할 수 있습니다.
Thread의 상태
- 경우에 따라서 스레드는 실행 상태에서 실행 대기 상태로 가지 않고 일시 정지 상태로 가기도 하는데, 일시 정지 상태는 스레드가 실행할 수 없는 상태입니다.
- 스레드가 다시 실행 상태로 가기위해서는 실행 대기 상태로 가야합니다.
스레드 객체 생성 - NEW
- 스레드 객체 생성 후 아직 start() 메서드가 호출되지 않은 상태입니다.
실행 대기 - RUNNABLE
- 실행 상태로 언제든지 갈 수 있는 상태입니다.
- CPU를 점유하고 있지 않으며 실행을 하기 위한 대기 상태입니다. 개발자가 start() 메서드를 호출하면 run() 메서드에 설정된 스레드가 준비상태로 진입합니다.
일시정지
- WAITING - 다른 스레드가 통지할 때까지 기다리는 상태입니다.
- TIMED_WAITING - 주어진 시간동안 기다리는 상태입니다.
- BLOCLED - 사용하고자 하는 객체의 락이 풀릴때까지 기다리는 상태입니다.
종료 - TERMINATED
- 실행을 마친 상태입니다.
Thread의 상태 예제
public class StatePrintThread extends Thread{
private Thread thread;
public StatePrintThread(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
while (true) {
Thread.State state = thread.getState();
System.out.println("스레드 상태: " + state);
if (state == Thread.State.NEW) {
thread.start();
}
if (state == Thread.State.TERMINATED) {
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TargetThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000000000; i++) {}
try {
Thread.sleep(1500);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 1000000000; i++) {}
}
}
public class Example {
public static void main(String[] args) {
StatePrintThread thread = new StatePrintThread(new TargetThread());
thread.start();
}
}
Thread의 상태 제어
sleep()
- 주어진 시간동안 일시정지 합니다.
- 일시 정지인 상태에서 interrupt() 메서드를 호출하면 InterruptedException 예외를 발생시켜 예외처리에서 실행 대기 상태로 가거나 종료상태로 갈 수 있습니다.
public class Example {
public static void main(String[] args) {
try {
Thread.sleep(1000);
System.out.println("Hello World");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
yieid()
- yieid() 메서드를 호출한 스레드는 실행대기 상태로 돌아가고 동일한 우선순위 또는 높은 우선순위를 갖는 다른 스레드가 실행될 기회를 줍니다.
public class ThreadA extends Thread{
boolean stop = false;
boolean work = true;
@Override
public void run() {
while (!stop) {
if (work) {
System.out.println("ThreadA가 작업중입니다.");
} else {
Thread.yield();
}
}
System.out.println("ThreadA가 종료되었습니다.");
}
}
public class ThreadB extends Thread{
boolean stop = false;
boolean work = true;
@Override
public void run() {
while (!stop) {
if (work) {
System.out.println("ThreadB가 작업중입니다.");
} else {
Thread.yield();
}
}
System.out.println("ThreadB가 종료되었습니다.");
}
}
public class Example {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.start();
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
threadA.work = false; // threadB만 실행
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
threadA.work = true; // threadA, threadB 둘다 실행
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
// 작업 종료
threadA.stop = true;
threadB.stop = true;
}
}
join()
- 다른 스레드가 종료될 때까지 기다렸다가 스레드를 실행할 경우 join() 메서드를 사용합니다.
public class SumThread extends Thread{
int sum;
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
sum += i;
}
}
}
public class Example {
public static void main(String[] args) {
SumThread sumThread = new SumThread();
sumThread.start();
try {
sumThread.join();
} catch (InterruptedException e) {}
System.out.println("1-100 합: " + sumThread.sum);
}
}
- join() 메서드를 제거하고 실행하면 sumThread가 작업을 완료하지 않은 상태에서 합을 먼저 출력을 하게 됩니다.
public class Example {
public static void main(String[] args) {
SumThread sumThread = new SumThread();
sumThread.start();
System.out.println("1-100 합: " + sumThread.sum);
}
}
wait(), notify(), notifyAll()
- 두개 이상의 스레드를 교대로 번갈아가며 실행해야하는 경우 자신의 작업이 끝나면 상대방 스레드의 일시 정지를 풀어주고, 자신은 일시 정지 상태로 만들어야 합니다. 이 방법의 핵심은 공유 객체에 있습니다.
- 공유 객체는 두 스레드가 작업할 내용을 각각 동기화 메서드로 구분해 놓고 한 스레드가 작업을 완료하면 notify() 메서드를 호출하여 일시 정지 상태에 있는 다른 스레드를 실행 대기 상태로 만들고 자신은 두번 작업을 하지 않도록 wait() 메서드를 호출하여 일시 정지 상태로 만듭니다.
- notify() 메서드와 동일한 역할을 하는 notifyAll() 메서드도 존재하는데 notify() 메서드는 wait()에 의해 일시 정지된 스레드 중 하나를 실행 대기 상태로 만들지만 notifyAll() 메서드는 wait() 메서드에 의해 일시 정지된 모든 스레드를 실행 대기 상태로 만듭니다.
- 해당 메서드들은 동기화 메서드 또는 동기화 블록 내부에서만 사용할 수 있습니다.
public class WorkObject {
public synchronized void methodA(){
System.out.println("ThreadA의 methodA() 작업 실행");
// 일시 정지 상태의 ThreadB를 실행 대기 상태로 만듬
notify();
try {
wait(); // ThreadA를 일시 정지 상태로 만듬
} catch (InterruptedException e) {}
}
public synchronized void methodB(){
System.out.println("ThreadB의 methodB() 작업 실행");
// 일시 정지 상태의 ThreadA를 실행 대기 상태로 만듬
notify();
try {
wait(); // ThreadB를 일시 정지 상태로 만듬
} catch (InterruptedException e) {}
}
}
public class ThreadA extends Thread{
private WorkObject workObject;
ThreadA(WorkObject workObject){
this.workObject = workObject;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
workObject.methodA();
}
}
}
public class ThreadB extends Thread{
private WorkObject workObject;
ThreadB(WorkObject workObject){
this.workObject = workObject;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
workObject.methodB();
}
}
}
public class Example {
public static void main(String[] args) {
WorkObject workObject = new WorkObject();
Thread threadA = new ThreadA(workObject);
Thread threadB = new ThreadB(workObject);
threadA.start();
threadB.start();
}
}
Thread의 우선 순위
멀티 스레드는 동시성 또는 병렬성으로 실행이 됩니다.
동시성(Concurrency)
- 동시성은 멀티 작업을 위해 하나의 코어에서 멀티 스레드가 번갈아가며 실행되는 성질입니다.
병렬성(Parallelism)
- 병렬성은 멀티 작업을 위해 멀티 코어에서 개별 스레드가 동시에 실행되는 성질을 말합니다.
- 자바의 스케줄링은 우선 순위 방식과 순환 할당 방식을 이용합니다.
우선순위 방식
- 우선순위가 높은 쓰레드가 실행 상태를 더 많이 가지도록 스케줄링하는 것을 말한다. 우선순위 방식은 객체에 우선 순위 번호를 부여할 수 있기 때문에 개발자가 코드로 제어를 할 수 있다.
- 우선순위는 1~10까지 부여되는데 1이 가장 우선순위가 낮고 10이 가장 높다. 참고로 기본 우선순위는 5이다. 우선순위를 설정하는 방법은 setPriority()메서드를 이용하면 된다.
순환 활당 방식
- 시간 할당량(Time Slice)을 정해서 하나의 쓰레드를 정해진 시간만큼 실행하고 다시 쓰레드를 실행시키는 방식을 말한다. 이 방식은 JVM에 의해서 정해지기 때문에 개발자가 코드로 제어할 수 없다.
public class CalcThread extends Thread{
CalcThread(String name){
setName(name);
}
@Override
public void run() {
for (int i = 0; i < 2000000000; i++) {}
System.out.println(getName());
}
}
public class Example {
public static void main(String[] args) {
for (int i = 0; i <= 10; i++) {
Thread thread = new CalcThread("thread - " + i);
if (i != 10) {
thread.setPriority(Thread.MAX_PRIORITY);
} else {
thread.setPriority(Thread.MAX_PRIORITY);
}
thread.start();
}
}
}
728x90
반응형
'JAVA > JAVA기본' 카테고리의 다른 글
JAVA - Enum이란? (0) | 2022.01.29 |
---|---|
JAVA - Main Thread란(feat.동기화, 데드락)? (0) | 2022.01.27 |
JAVA - Thread 클래스와 Runnable 인터페이스 (0) | 2022.01.27 |
JAVA - 예외 처리(try, catch, throw, throws, finally) (0) | 2022.01.26 |
JAVA - 인터페이스란? (0) | 2022.01.26 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- transactional outbox pattern
- 람다 표현식
- 레이어드 아키텍처란
- 서비스 기반 아키텍처
- spring boot redisson destributed lock
- 트랜잭셔널 아웃박스 패턴 스프링부트
- spring boot poi excel download
- java userThread와 DaemonThread
- java ThreadLocal
- 자바 백엔드 개발자 추천 도서
- spring boot 엑셀 다운로드
- service based architecture
- spring boot excel download oom
- spring boot redisson 분산락 구현
- polling publisher spring boot
- spring boot redisson sorted set
- pipe and filter architecture
- space based architecture
- redis 대기열 구현
- 공간 기반 아키텍처
- microkernel architecture
- redis sorted set
- spring boot excel download paging
- JDK Dynamic Proxy와 CGLIB의 차이
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- @ControllerAdvice
- pipeline architecture
- spring boot redis 대기열 구현
- redis sorted set으로 대기열 구현
- transactional outbox pattern spring boot
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함