✍️ Java Concurrent 프로그래밍
- 동시에 여러 작업을 할 수 있는 소프트웨어
- 예) 웹 브라우저로 유튜브를 보면서 키보드로 문서에 타이핑을 할 수 있음
- 예) 이클립스에 코드를 타이핑하면 코드가 입력됨과 동시에 추천 코드를 제안함
- 자바에서 지원하는 Concurrent 프로그래밍
- 멀티 프로세싱 (ProcessBuilder)
- 멀티 쓰레드 (본 포스팅에서 다룰 주제)
- 자바 멀티 쓰레드 프로그래밍
- Thread
- Runnable
🍊 자바 멀티 쓰레드 프로그래밍
Java 프로세스의 기본 쓰레드는 main 쓰레드다.
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
}
// main
하나의 쓰레드에서 다른 쓰레드를 만들 수 있는데, 크게 두 가지 방법이 존재한다.
첫째로 Thread를 상속하는 방법
둘째로 Runnable을 구현하는 방법
Thread를 상속받는 코드부터 살펴보면, Thread를 상속받은 MyThread의 인스턴스를 만들고 start를 호출하면 쓰레드가 생성된다.
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println("main Thread : " + Thread.currentThread().getName());
}
static class MyThread extends Thread{
@Override
public void run() {
System.out.println("new Thread : " + Thread.currentThread().getName());
}
}
// main Thread : main
// new Thread : Thread-0
순서상 new Thread : Thread-0가 main Thread : main보다 먼저 출력돼야 할 것 같지만 쓰레드의 자원 할당은 OS에 의해 결정되므로 항상 어떤 쓰레드가 먼저 실행될 것이라고 보장할 수 없다.
// 자바 8 스타일
Thread thread = new Thread(() -> {
System.out.println("람다식 new Thread : " + Thread.currentThread().getName());
});
thread.start();
// 자바8 이전 방식
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("익명 구현 객체 new Thread : " + Thread.currentThread().getName());
}
});
thread.start();
❗️ 쓰레드의 주요 기능
sleep, 현재 쓰레드 대기시키기
현재 쓰레드를 대기시키면 다른 쓰레드가 자원을 할당받아 일을 하고 대기가 끝나면 다시 자원을 할당받아 일을 한다.
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("람다식 new Thread : " + Thread.currentThread().getName());
});
thread.start();
System.out.println("main Thread : " + Thread.currentThread().getName());
// 매우 높은 확률로 main Thread 로그가 먼저 찍힘
interrupt, 다른 쓰레드 깨우기
try-catch문을 보면 InterruptedException이 보인다. 쓰레드가 자는 동안 누군가가 자신을 깨우면 InterruptedException이 발생한다. 그렇다면 자고 있는 쓰레드를 깨울 수 있는 방법이 존재한다는 건데 그게 바로 interrupt 메서드다.
Thread thread = new Thread(() -> {
while(true) {
System.out.println("반복중... : " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("interrupt!!");
return;
}
}
});
thread.start();
System.out.println("main Thread : " + Thread.currentThread().getName());
Thread.sleep(3000);
thread.interrupt();
// main Thread : main
// 반복중... : Thread-0
// 반복중... : Thread-0
// 반복중... : Thread-0
// interrupt!!
join, 다른 쓰레드가 끝날 때까지 기다리기
다른 쓰레드가 끝날 때까지 기다리려면 join을 사용하면 된다.
Thread thread = new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
});
thread.start();
System.out.println("waiting for " + thread.getName());
thread.join();
System.out.println("finished : " + thread.getName());
// waiting for Thread-0
// finished : Thread-0
그런데 만약, 다른 쓰레드가 끝나길 기다리는 main 쓰레드를 누군가가 interrupt 한다면 마찬가지 InterruptedException이 발생한다.
👋 정리,
지금까지 자바 멀티 쓰레드 프로그래밍의 처리 방법에 대해 알아봤다.
두 개의 쓰레드만 만들어도 코드가 복잡한데 쓰레드가 10개 100개인 프로그램에서 쓰레드를 하나하나 직접 관리할 수 있을까? 하물며 여기저기서 발생하는 interrupt 그리고 이로 인해 발생하는 InterruptedException은 개발을 어렵게 만든다.
이처럼 여러 쓰레드를 개발자가 하나하나 관리할 수 없다는 문제를 해결하기 위해 Executors가 등장했고, Executors의 사용법을 익히면 Future를 사용할 수 있게 되고, Future의 사용법을 익히면 그제서야 Chapter6의 목적지인 CompletableFuture를 사용할 수 있게 된다.
'Java > Java 8' 카테고리의 다른 글
[Java8] Chapter 6-3. Callable과 Future (0) | 2022.03.02 |
---|---|
[Java8] Chapter 6-2. Executors (0) | 2022.03.01 |
[Java8] Chapter 5-2. Date와 Time 실습 (2) (0) | 2022.02.23 |
[Java8] Chapter 5-1. Date와 Time (1) (0) | 2022.02.22 |
[Java8] Chapter 4-2. Optional API 실습 (2) (0) | 2022.02.21 |