1. 멀티 프로세스와 멀티 스레드
▷ 프로세스 : 운영체제는 실행 중인 프로그램을 관리
▷ 멀티 태스킹 : 두 가지 이상의 작업을 동시에 처리하는 것
▷ 스레드 : 코드의 실행 흐름
▷ 멀티 스레드 : 두 개의 코드 실행 흐름. 두 가지 이상의 작업을 처리
▷ 멀티 프로세스 : 프로그램 단위의 멀티 태스킹 / 멀티 스레드 : 프로그램 내부에서의 멀티 태스킹
2. 메인 스레드
▷ 메인 스레드는 main() 메소드의 첫 코드부터 순차적으로 실행
▷ main() 메소드의 마지막 코드를 실행하거나 return 문을 만나면 실행 종료
▷ 메인 스레드는 추가 작업 스레드들을 만들어서 실행시킬 수 있음
▷ 메인 스레드가 작업 스레드보다 먼저 종료되더라도 작업 스레드가 계속 실행 중이라면 프로세스는 종료되지 않음.
3. 작업 스레드
▷ 작업 스레드 : 멀티 스레드 프로그램을 개발 시 먼저 몇 개의 작업을 병렬로 실행할지 결정하고 각 작업별로 스레드를 생성
◎ Thread 클래스로 직접 생성
▷ java.lang 패키지에 있는 Thread 클래스로부터 작업 스레드 객체를 직접 생성하려면 Runnable 구현 객체를 매개값으로 갖는 생성자를 호출
Thread thread = new Thread(Runnalbe target);
// Thread 클래스로 직접 생성 // 러너블 구현 객체를 매개값으로 같는 생성자 호출 Thread thread = new Thread(Runnable target); // 러너블 인터페이스와 run 메소드 사용 class Task implements Runnable { @Override public void run() { // 스레드가 실행할 코드 } } // 러너블 객체 생성 Runnable task = new Task(); // 스레드 객체 생성(러너블 객체를 매개값으로 사용) Thread thread = new Thread(task); // 익명으로 사용 Thread thread = new Thread(new Runnable() { @Override public void run() { // 스레드가 실행할 코드 } }); // 스레드 동작 실행 thread.start();
◎ Thread 클래스로 직접 생성 예시 1
import java.awt.Toolkit; public class BeepPrintExample { public static void main(String[] args) { Toolkit toolkit = Toolkit.getDefaultToolkit(); for(int i=0; i<5; i++) { toolkit.beep(); try { Thread.sleep(500); } catch(Exception e) {} } for(int i=0; i<5; i++) { System.out.println("띵"); try { Thread.sleep(500); } catch(Exception e) {} } } }
▷ Toolkit 클래스의 beep 메소드를 사용하면 소리가 납니다.
▷ 소리가 5번 울리면 '띵' 이라는 글자가 5번 나타납니다.
◎ Thread 클래스로 직접 생성 예시 2
import java.awt.Toolkit; public class BeepPrintExample1 { 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) {} } } }
▷ 소리가 울릴때 마다 글자가 나타나는 것처럼 보입니다.(동작은 별개입니다.)
4. Thread 이름
▷ Thread 클래스를 상속한 다음 run() 메소드를 재정의해서 스레드가 실행할 코드를 작성하고 객체를 생성
▷ 혹은 Thread 익명 자식 객체를 사용 가능
▷ 작업 스레드 이름을 thread-n 대신 다른 이름으로 설정하려면 Thread 클래스의 setName() 메소드 사용
▷ 어떤 스레드가 실행하고 있는지 확인 하려면 정적 메소드인 currentThread()로 스레드 객체의 참조를 얻습니다.
→ 이후 getName() 메소드로 이름을 출력합니다.
public class ThreadNameExample { public static void main(String[] args) { Thread mainThread = Thread.currentThread(); System.out.println(mainThread.getName() + "실행"); for(int i=0; i<3; i++) { Thread threadA = new Thread() { @Override public void run() { System.out.println(getName() + "실행"); } }; threadA.start(); } Thread chatThread = new Thread() { @Override public void run() { System.out.println(getName() + "실행"); } }; chatThread.setName("chat-thread"); chatThread.start(); } } // 출력 : // main실행 // Thread-0실행 // Thread-1실행 // chat-thread실행 // Thread-2실행
▷ main이 가장 먼저 실행되고 나머지는 순서가 지속적으로 바뀌면서 실행됩니다.
▷ 작업 스레드는 'Thread-n'이라는 이름을 자동적으로 가지고 있습니다.
▷ 이름 변경하기 위해서는 setName을 사용하면 됩니다.
5. 스레드 상태
▷ 실행 대기 상태 : 실행을 기다리고 있는 상태
▷ 시행 상태 : CPU 스케줄링에 따라 CPU를 점유하고 run() 메소드를 실행.
→ 스케줄링에 의해 다시 실행 대기 상태로 돌아갔다가 다른 스레드가 실행 상태 반복
▷ 종료 상태 : 실탱 상태에서 run() 메소드가 종료되어 실행할 코드 없이 스레드의 실행을 멈춘 상태
◎ 일시 정지 상태
▷ 스레드가 실행할 수 없는 상태
▷ 스레드가 다시 실행 상태로 가기 위해서는 일시 정지 상태에서 실행 대기 상태로 가야함
▷ Thread 클래스의 sleep() 메소드 : 실행 중인 스레드를 일정 시간 멈추게 함
▷ 매개값 단위는 밀리세컨드(1/1000)
NO | 구분 | 메소드 | 설명 |
1 | 일시 정지로 보냄 | sleep(long millis) | 주어진 시간동안 스레드를 일시 정지 상태로 만듭니다. 주어진 시간이 지나면 자동적으로 실행 대기 상태가 됩니다. |
2 | join() | join() 메소드를 호출한 스레드는 일시 정지 상태가 됩니다. 실행 대기 상태가 되려면, join() 메소드를 가진 스레드가 종료되어야 합니다. |
|
3 | wait() | 동기화 블록 내에서 스레드를 일시 정지 상태로 만듭니다. | |
4 | 일시 정지에서 벗어남 |
interrupt() | 일시 정지 상태일 경우, InterruptedException을 발생시켜 실행 대기 상태 또는 종료 상태로 만듭니다. |
5 | notify() notifyAll() |
wait() 메소드로 인해 일시 정지 상태인 스레드를 실행 대기 상태로 만듭니다. | |
6 | 실행 대기로 보냄 | yield() | 실행 상태에서 다른 스레드에게 실행을 양보하고 실행 대기 상태가 됩니다. |
◎ 일시 정지 예시
import java.awt.Toolkit; public class SleepExample { public static void main(String[] args) { Toolkit toolkit = Toolkit.getDefaultToolkit(); for(int i=0; i<10; i++) { toolkit.beep(); try { Thread.sleep(3000); } catch(InterruptedException e) {} } } }
sleep을 이용해 3초 동안 main을 일시 정지 시킵니다.
◎ 일시 정지 예시 2
1. SumThread 클래스
public class SumThread extends Thread{ private long sum; public long getSum() { return sum; } public void setSum(long Sum) { this.sum = sum; } @Override public void run() { for(int i=1; i<=100; i++) { sum+=i; } } }
2. JoinExample 메인 클래스
import java.awt.Toolkit; public class JoinExample { public static void main(String[] args) { SumThread sumThread = new SumThread(); sumThread.start(); try { sumThread.join(); } catch(InterruptedException e) { } System.out.println("1~100 합 : " + sumThread.getSum()); } } // 출력 : // 1~100 합 : 5050
▷ start만 하면 0이 출력되고 join을 통해 일시 정지하면 100까지의 합이 출력됩니다.
◎ 다른 스레드에게 실행 양보
▷ yield() 메소드 : 실행되는 스레드는 실행 대기 상태로 돌아가고, 다른 스레드가 실행되도록 양보합니다.
▷ 무의미한 반복을 막아 프로그램 성능을 향상시킵니다.
◎ 실행 양보 예제
1. WorkThread 클래스
public class WorkThread extends Thread { public boolean work = true; // 생성자 public WorkThread(String name) { setName(name); } // 메소드 public void run() { while(true) { if(work) { System.out.println(getName() + ": 작업처리"); } else { Thread.yield(); } } } }
2. YieldExample 메인 클래스
public class YieldExample { public static void main(String[] args) { WorkThread workThreadA = new WorkThread("workThreadA"); WorkThread workThreadB = new WorkThread("workThreadB"); workThreadA.start(); workThreadB.start(); try { Thread.sleep(5000); } catch (InterruptedException e) {} workThreadA.work = false; try { Thread.sleep(10000); } catch (InterruptedException e) {} workThreadA.work = true; } }
▷ A와 B가 번갈아 나오고 5초 뒤 B가 많이 나옵니다.
▷ 그 후 10초 뒤 A, B가 다시 번갈아가며 나옵니다.
스레드가 동작하는 것에 대해 코드로 구현해 보았습니다.
스레드는 순서대로 동작하는 것이 아니라 먼저 입력받는 것을 출력하는 것을 알았습니다.
다음 글에서 더 다뤄봅시다!!
단축키 팁!
control + shift + O : 필요한 import 자동 생성
많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~
'BackEnd > Java' 카테고리의 다른 글
[java] 이것이 자바다 ch15 컬렉션 1 (0) | 2023.01.25 |
---|---|
[java] 이것이 자바다 ch14 스레드(thread) 2 (0) | 2023.01.25 |
[백준 문제 2941번] 크로아티아 알파벳 문제 (0) | 2023.01.24 |
[백준 문제 1152번] 단어의 개수 문제 (0) | 2023.01.22 |
[java] 스레드(Thread) (0) | 2023.01.21 |