티스토리 뷰
14.1 멀티 스레드 개념
- 운영체제는 실행 중인 프로그램을 프로세스로 관리
- 멀티 태스킹은 두 가지 이상의 작업을 동시에 처리하는 것을 말함
- 스레드는 코드의 흐름을 말함
- 하나의 프로세스가 두 가지 이상의 작업을 처리할 수 있는 이유는 멀티 스레드가 있기 때문이다.
- 멀티 프로세스가 프로그램 단위의 멀티 태스킹이라면 멀티 스레드는 프로그램 내부에서의 멀티 태스킹이라고 볼 수 있다.
- 멀티 프로세스는 서로 독립적이므로 다른 프로세스에게 영향을 미치지 않음
- 멀티 스레드는 프로세스 내부에 생성되기 때문에 하나의 스레드가 예외를 발생시키면 다른 스레드에도 영향을 미친다.
14.2 메인 스레드
- 메인 스레드가 main()메소드를 실행하면서 실행
main() 메소드 첫 코드부터 순차적으로 실행 - 필요에 따라 추가 작업 스레드들을 만들어서 실행 가능
- 싱글 스레드에서는 메인 스레드가 종료되면 프로세스 종료
- 멀티 스레드에서는 실행 중인 스레드가 하나라도 있으면 프로세스는 종료되지 않는다.
14.3 작업 스레드 생성과 실행
- 작업 스레드도 객체로 관리하므로 클래스가 필요
Thread 클래스로 직접 생성
- Runnable구현 객체를 매개값으로 갖는 생성자를 호출
- Runnable은 스레드가 작업을 실행할 때 사용하는 인터페이스
- Runnable 안에 있는 run() 에 스레드가 실행할 코드를 재정의
public class BeepPrintDemo {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Toolkit toolkit = Toolkit.getDefaultToolkit();
for (int i = 0; i < 5; i++) {
toolkit.beep();
try { Thread.sleep(500); } catch (Exception e) {}
}
}
});
// 스레드 시작
thread.start();
// 메인 스레드 시작
for (int i = 0; i < 5; i++) {
System.out.println("띵");
try { Thread.sleep(500); } catch (Exception e) {}
}
}
}
Thread 자식 클래스로 생성
package beginnerJava.src.ch14;
import java.awt.*;
public class BeepPrintDemo2 {
public static void main(String[] args) {
// Thread의 익명 자식 객체로 작업 스레드를 정의
Thread thread = new Thread() {
@Override
public void run() {
Toolkit toolkit = Toolkit.getDefaultToolkit();
for (int i = 0; i < 5; i++) {
toolkit.beep();
try { Thread.sleep(500); } catch (Exception e) {}
}
}
};
thread.start();
for (int i = 0; i < 5; i++) {
System.out.println("띵");
try { Thread.sleep(500); } catch (Exception e) {}
}
}
}
14.4 스레드 이름
- 스레드는 자신의 이름을 가지고 있다 -> 메인 스레드는 main / 작업 스레드는 자동적으로 Thread-n
// 이 코드를 실행하는 스레드 객체 참조를 얻음
Thread thread = Thread.currentThread();
// 현재 실행하고 있는 스레드의 이름 확인
thread.getName();
// 스레드 이름 설정
thread.setName("스레드 이름");
14.5 스레드 상태
- 스레드 객체를 생성(new)하고 start() 메소드를 호출하면 스레드가 실행되는 것이 아니라 대기 상태가 된다.
- 실행 대기 상태에서 스레드는 CPU 스케줄링에 따라 CPU를 점유하고 run() 메소드를 실행 -> 실행 상태로 전환
- 실행 스레드는 run() 메소드를 모두 종료하기 전에 실행 대기 상태로 돌아갈 수 있고 대기와 실행을 반복하면서 run() 메소드를 실행
- run() 메소드가 종료되면 종료 상태가 된다.
- 실행 상태에서 일지 정지 상태로 가기도 하는데, 일시 정지 상태는 스레드가 실행할 수 없는 상태
- 일시 정지 상태엣 실행 상태로 가기 위해서는 실행 대기 상태로 가야만 한다.
주어진 시간 동안 일시 정시 sleep()
- 주어진 시간 동안 스레드를 일시 정지 상태로 만들고 시간이 지나면 자동적으로 실행 대기 상태가 된다.
다른 스레드의 종료를 기다림 join()
Thread A
// threadB 스레드 시작
threadB.start();
// threadB 스레드가 종료할 때까지 Thread A는 기다린다. (일시 정지 상태가 된다)
threadB.join();
// threadB 의 run() 메소드가 완료되면 Thread A의 일시 정지 상태가 풀려 다음 코드 실행
threadB.run()
다른 스레드에게 실행 양보 yield()
- 실행 상태에서 다른 스레드에게 실행을 양보하고 실행 대기 상태가 된다.
14.6 스레드 동기화
- 멀티 스레드는 하나의 객체를 공유해서 작업할 수도 있음
- 스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없도록 스레드의 작업이 끝날 때까지 객체를 잠글 수 있음 -> 동기화 메소드와 블록
동기화 메소드 및 블록 선언: synchronized 키워드 사용
// 동기화 메소드
synchronized void method(){
// 단 하나의 스레드만 실행
}
void mehtod2(){
// 여러 스레드 실행 가능
synchronized(공유 객체) {
// 단 하나의 스레드만 실행
}
}
wait() 과 notify() 를 이용한 스레드 제어
- wait(): 스레드를 일시 정지 상태로 만든다.
- notify(): wait() 메소드로 인해 일시 정지된 스레드를 실행 대기 상태로 만든다.
- 두 함수를 이요해 스레드를 교대로 번갈아 가며 실행
- 이 두 메소드는 동기화 메소드 또는 동기화 블록 내에서만 사용 가능
14.7 스레드 안전 종료
- 예전에는 강제 종료를 위해 stop() 메소드를 사용했으나 사용 중이던 리소스들이 불안전한 상태로 남겨지기 때문에 deprecated 되었다.
- 스레드를 안전하게 종료하는 방법은 리소스들을 정리하고 run()메소드를 빨리 종료한다
방법1) 조건 이용 방법
- 조건을 이용해 run()메소드 종료를 유도
방법2) interrupt() 메소드 이용 방법
- 스레드가 일시 정지 상태에 있을 때 InterrruptedException예외를 발생시켜 run() 메소드를 정상 종료
- 실행 대기 / 실행 상태일 때는 InterrruptedException 예외 발생하지 않음
14.8 데몬 스레드
- 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드
- 주 스레드가 종료되면 데몬 스레드도 따라서 자동 종료
- 주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출하면 된다.
14.9 스레드풀
- 스레드의 개수가 늘고 CPU가 바빠져 메모리 사용량이 증가하면 애플리케이션의 성능 또한 저하된다
- 스레드풀은 작업 처리에 사용되는 스레드를 제한된 개수만큼 정해놓고 작업 큐에 들어오는 작업들을 스레드가 하나씩 맡아 처리하는 방식
스레드풀 생성
// 60초 동안 스레드가 아무 작업을 하지 않으면 스레드를 풀에서 제거한다.
ExecutorService executorService = Executors.newCachedThreadPool();
// 생성된 스레드를 제거하지 않는다.
ExecutorService executorService = Executors.newFixedThreadPool(5);
// ThreadPoolExecutor로 스레드풀 생성 가능
ExecutorService executorService = new ThreadPoolExecutor(
3,
100,
120L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>()
);
- 초기 수: 스레드풀이 생성될 떄 기본적으로 생성되는 스레드 수
- 코어 수: 스레드가 증가된 후 사용되지 않는 스레드를 제거할 때 최소한 풀에서 유지하는 스레드 수
- 최대 수: 증가되는 스레드의 한도 수
스레드풀 종료
- 데몬 스레드가 아니기 때문에 maid 스레드가 종료되도 작업을 처리하기 위해 계속 실행 상태로 남아 있음
- shutdown(): 작업 큐에 대기하고 있는 모든 작업을 처리하고 스레드풀 종료
- shutdownNow(): 남아있는 작업과는 상관없이 강제로 종료 . 작업 큐에 있는 미러치된 작업 목록을 리턴함
작업 생성과 처리 요청
- Runnable: 작업 처리 결과를 리턴하지 않음
- Callable: 작업 처리 결과를 얻을 수 있도록 Future를 리턴
'도서 및 강의 > 이것이 자바다' 카테고리의 다른 글
이것이 자바다 3판 챕터 16 람다식 (0) | 2024.09.18 |
---|---|
이것이 자바다 3판 챕터 15 (0) | 2024.09.18 |
이것이 자바다 3판 챕터 13 (0) | 2024.09.18 |
이것이 자바다 3판 챕터 12 (0) | 2024.09.18 |
이것이 자바다 3판 챕터 11 (0) | 2024.09.18 |
최근에 올라온 글