반응형
💋 인트로
과거의 컴퓨터는 한 번에 하나의 작업만 가능했다.
사진을 다운로드 받는 작업, 마우스나 키보드로부터 입력을 받는 작업, 브라우저로 사이트를 돌아다니는 작업을 동시에 할 수 없었다.
이후 컴퓨터는 동시에 여러 개의 작업을 하는 멀티태스킹이 가능해졌다.
배경에 있는 프로세스, 쓰레드에 대해 알아보자.
💋 개념
- 프로세스
- 실행중인 프로그램
- 프로그램을 실행하면 OS로부터 자원(메모리)을 할당받아 프로세스가 됨.
- 쓰레드
- 프로세스의 자원을 이용해 실제로 작업을 수행하는 것
- 프로세스의 구성
- 자원(데이터, 메모리) + 쓰레드
- 모든 프로세스는 1개 이상의 쓰레드가 존재
- 2개 이상의 쓰레드를 가진 프로세스는 ‘멀티 쓰레드 프로세스’
- 자원(데이터, 메모리) + 쓰레드
💋 멀티쓰레딩의 장단점
- 장점
- CPU 사용률 향상
- 자원을 효율적으로 사용할 수 있음.
- 하나의 작업을 하는 동안에도 다른 작업을 수행할 수 있음.
- 사용자에 대한 응답성 향상
- 하나의 작업을 하는 동안에도 다른 작업에 응답할 수 있음.
- 작업이 분리되어 코드가 간결해짐.
- 단점
- 여러 쓰레드가 같은 프로세스 내에서 자원을 공유하면서 작업함.
- 동기화(synchronization) 문제 발생 가능
- 교착상태(deadlock) 문제 발생 가능
- 두 쓰레드가 자원을 점유한 상태에서 서로 상대편이 점유한 자원을 사용하려고 기다리느라 진행이 멈춰있는 상태
- 단순히 시간만 비교해 보았을 때, 싱글 쓰레드에 비해 오래 걸림.
- context switching에 시간이 걸리기 때문
- 전환을 위해서는 현재 진행중인 작업의 상태의 정보를 저장하고 읽어오는 데에 시간이 걸림.
- 여러 쓰레드가 같은 프로세스 내에서 자원을 공유하면서 작업함.
💋 Java의 Thread 구현
✔ 생성
Thread
클래스를 상속해서 구현
public class MyThread extends Thread {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.run();
}
@Override
public void run() {
System.out.println("쓰레드 시작!");
}
}
Runnable
인터페이스를 구현
public class MyThread implements Runnable {
public static void main(String[] args) {
Runnable runnable = new MyThread();
Thread thread = new Thread(runnable); // 생성자 Thread(Runnable runnable)
thread.run();
}
@Override
public void run() {
System.out.println("쓰레드 시작!");
}
}
✔ 실행: start()
public static void main(String[] args) {
Runnable runnable = new MyThread();
Thread thread = new Thread(runnable);
thread.start();
}
start()
를 호출해 쓰레드 실행- 실행 대기 상태에 있다가, 자신의 차례가 되면 실행됨.
- 실행 순서는 OS 스케줄러의 스케줄에 따름.
- 한 번 실행이 종료된 쓰레드는 다시 실행할 수 없음.
- 하나의 쓰레드에 두 번 이상
start()
를 호출하면,IllegalThreadStateException
발생
- 하나의 쓰레드에 두 번 이상
✔ start()
vs run()
start()
- 쓰레드를 실행함.
- 쓰레드가 작업을 하는데 필요한 호출 스택(call stack)을 생성한 후에 run()을 호출해서, 생성된 호출스택에 run()이 첫번째로 올라가게 함.
run()
- 단순히, 클래스에 선언된 메서드를 호출함.
- main 메서드에서 쓰레드의 start() 호출
- start()가 새로운 쓰레드를 생성 + 쓰레드가 작업할 호출 스택 생성
- 새로운 호출스택에 run() 호출되어, 쓰레드가 독립된 공간에서 작업 수행
- 호출 스택이 2개이므로 OS 스케줄러의 스케줄에 따라 번갈아가면서 실행
✔ main 쓰레드
- main 메서드의 작업을 실행하는 것도 쓰레드임.
- 프로그램의 실행을 위해 수행하는 쓰레드가 적어도 1개 있어야 함.
- 해당 쓰레드가 main 메서드를 호출해, 작업이 수행되도록 함.
💋 싱글 쓰레드 VS 멀티 쓰레드
✔ 싱글 쓰레드
public class SingleThread {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 300; i++) {
System.out.printf("%s", new String("?"));
}
long time1 = System.currentTimeMillis() - startTime;
System.out.println("time1 = " + time1);
for (int i = 0; i < 300; i++) {
System.out.printf("%s", new String("!"));
}
long time2 = System.currentTimeMillis() - startTime;
System.out.println("time2 = " + time2);
}
}
결과
> Task :tomcat:SingleThread.main()
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????time1 = 26
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!time2 = 37
- 두 개의 쓰레드가 작업을 하나씩 차례대로 수행함.
✔ 멀티 쓰레드
public class MultiThread {
static long startTime = 0;
public static void main(String[] args) {
Runnable runnable = new MyThread();
Thread thread = new Thread(runnable);
thread.start();
startTime = System.currentTimeMillis();
for (int i = 0; i < 300; i++) {
System.out.printf("%s", new String("!"));
}
long time1 = System.currentTimeMillis() - MultiThread.startTime;
System.out.println("time1 = " + time1);
}
static class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.printf("%s", new String("?"));
}
long time2 = System.currentTimeMillis() - MultiThread.startTime;
System.out.println("time2 = " + time2);
}
}
}
결과
> Task :tomcat:MultiThread.main()
!!!!!!!????????????????????????????????????????????????????!?????????????!!!!!!!!!!!!!!!!!!!!!!!!!???!!!!!!!!!!!!!!!!!!!!!!!!!!??????????????????????????????!!!!!!!!!!!!!!!!!!!!!!????????????????????????????????????????????????????????????????????????????????????????????????????????!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!????!!!??????????????????????????????????????????????????!!!?????????????????????????????????!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!???????????!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!time2 = 32
- 두 작업이 아주 짧은 시간 동안 번갈아가면서 실행되고, 거의 도잇에 완료됨.
💋 I/O Blocking
- 쓰레드가 입출력 처리를 위해 기다리는 것
- 사용자로부터 입력받는 작업과 화면에 출력하는 작업을 하나의 쓰레드로 처리한다면, 해당 쓰레드는 사용자가 입력을 마칠 때까지 아무런 일도 하지 못하게 되므로, 멀티 쓰레드로 처리하는 것이 효율적임.
✔ 싱글 쓰레드
public class ThreadIOBlocking {
public static void main(String[] args) throws InterruptedException {
// 사용자로부터 입력받기
String input = JOptionPane.showInputDialog("값을 입력해 주세요.");
System.out.println("input = " + input);
// 화면에 숫자를 출력하기
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
Thread.sleep(1000);
}
}
}
- 사용자가 값을 입력할 때까지 화면에 숫자가 출력되지 않음.
✔ 멀티 쓰레드
public class MultiThread {
public static void main(String[] args) {
Runnable runnable = new MyThread();
Thread thread = new Thread(runnable);
thread.start();
// 사용자로부터 입력받기
String input = JOptionPane.showInputDialog("값을 입력해 주세요.");
System.out.println("input = " + input);
}
static class MyThread implements Runnable {
@Override
public void run() {
// 화면에 숫자를 출력하기
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
}
}
}
}
- 사용자가 입력을 마치지 않아도 화면에 숫자가 출력되기 시작함.
💋 참고자료
- 자바의 정석 2편
반응형
'JAVA' 카테고리의 다른 글
[JAVA] 멀티 쓰레드의 동기화(synchronization): 메서드, 메서드 내 블록에 synchronized 키워드를 붙이자! (0) | 2023.09.10 |
---|---|
[JAVA] 쓰레드 풀(Thread Pool): 개념, 장점, 사용 방법, 코드 예시 (feat. Baeldung) (0) | 2023.09.09 |
[JAVA] 좋은 객체 지향 설계의 5가지 원칙 (SOLID) (0) | 2023.05.01 |
[Spring] Spring Core(3): IoC Container의 개념, 생명 주기 (2) | 2023.04.23 |
[JAVA] 좋은 코드가 되려면 꼭 지켜야 할 기본적인 컨벤션 (0) | 2023.04.13 |