- 동작하고 있는 프로그램을 프로세스(Process)라고 한다. 보통 한 개의 프로세스는 한 가지의 일을 하지만, 쓰레드를 이용하면 한 프로세스 내에서 두 가지 또는 그 이상의 일을 동시에 할 수 있다.
- Java는 스레드 스케줄러가 스레드의 우선 순위에 따라 스레드에 프로세서를 할당하는 멀티스레딩 환경 내에서 완전히 객체 지향적으로 작동
✨ (주의) 우리는 run 메서드를 직접 호출하지 않고, start()만 수행
void run()
void start()
쓰레드 실행 순서 ✨
시작
준비
단계: 쓰레드 객체를 생성한 후 start() 메서드를 호출합니다. 이 때, JVM은 해당 쓰레드를 실행 가능한 상태인 "Runnable" 상태로 만들고, 해당 쓰레드가 사용할 스레드 스택(Thread Stack)을 생성합니다.Block
단계: 쓰레드가 실행 가능한 상태가 되면, 스케줄러(Scheduler)
에 의해 CPU가 할당되고, 해당 쓰레드가 실행됩니다. 실행 중인 쓰레드가 다른 쓰레드에 의해 중지되는 경우, 해당 쓰레드는 "Block" 상태로 변경됩니다.Wait
단계: 쓰레드가 Block 상태에 있을 때, 일시적으로 실행을 중단하고 다른 쓰레드의 notify() 메서드 호출을 기다리는 경우, 해당 쓰레드는 "Wait" 상태로 변경됩니다. 이 때, 쓰레드는 wait() 메서드를 호출하여 일시적으로 실행을 중단합니다.Notify
단계: Wait 상태에 있는 쓰레드가 다시 실행되기 위해서는, 다른 쓰레드가 notify() 메서드를 호출해야 합니다. 이 때, notify() 메서드를 호출하는 쓰레드와 wait() 메서드를 호출한 쓰레드는 동일한 객체의 모니터를 공유해야 합니다.제거
단계: 쓰레드가 실행을 마치면, 해당 쓰레드는 종료됩니다. 이 때, JVM은 해당 쓰레드가 사용한 자원을 해제하고, 해당 쓰레드의 스택을 제거합니다.자바에서 동기화(synchronization)는 공유 자원에 대한 접근을 제한하고, 여러 쓰레드가 공유 자원에 동시에 접근하는 것을 방지하는 기술
자바에서는 동기화를 위해 synchronized 키워드와 wait(), notify(), notifyAll() 메서드를 제공
이 중 wait(), notify(), notifyAll() 메서드는 Object 클래스에서 제공되며, 다음과 같은 실행 순서를 지님 (개념만 알기)
package p01;
class Go{
public void go() {
while(true) {
System.out.println("go");
}
}
}
// go class와 come class 간의 병행성이 없는 상태 => 스레드 생성을 통해 병행 처리 가능
class Come{
public void come() {
while(true) {
System.out.println("come");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Go g = new Go();
Come c = new Come();
g.go();
c.come();
}
}
package p02;
class Go extends Thread{
public void run() {
while(true) {
System.out.println("go" + Thread.currentThread().getName());
}
}
}
// go class와 come class 간의 병행성이 없는 상태 => 스레드 생성을 통해 병행 처리 가능
class Come extends Thread{
public void run() {
while(true) {
System.out.println("come" + Thread.currentThread().getName());
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Go g = new Go();
Come c = new Come();
g.start();
c.start();
}
}
준 스레드
상태) package p03;
// implements Runnable 주의 사항: Go는 아직 스레드가 아님 (`준 스레드` 상태)
class Go implements Runnable{
// run 메서드 재정의 필
public void run() {
while(true) {
System.out.println("go");
}
}
}
// implements Runnable 주의 사항: Go는 아직 스레드가 아님 (`준 스레드` 상태)
class Come implements Runnable{
public void run() {
while(true) {
System.out.println("come");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
// 아직 스레드가 아니다
Go g = new Go();
Come c = new Come();
// g.start(); => start는 스레드에만 있는 메서드라 준 스레드에서 실행 불가능
// 진짜 스레드로 생성
Thread t1 = new Thread(g, "go thread");
Thread t2 = new Thread(c, "come thread");
// 스레드 우선권 확인
System.out.println("t1 우선권" + t1.getPriority());
System.out.println("t2 우선권" + t2.getPriority());
// 우선권 변경
t1.setPriority(10);
// 실행시 스레드를 이용한 병행 처리 결과와 동일
t1.start();
t2.start();
}
}
사용자 지정 스레드 명칭 부여
실행 결과
스레드 우선권 확인
// 스레드 우선권 확인
System.out.println("t1 우선권" + t1.getPriority());
System.out.println("t2 우선권" + t2.getPriority());
// 우선권 변경
t1.setPriority(10);
package p04;
public class ThreadTest {
// main 함수도 스레드에 의해 실행되고 있는 것임
// 즉, main 스레드가 main 메소드를 실행시키고 있음
// 우리가 직접 스레드를 만들지 않아도 자동으로(background) 생성되는 스레드가 main 스레드임
public static void main(String[] args) {
// main 스레드가 main 메서드 실행
System.out.println(Thread.currentThread().getName()); // main
System.out.println(Thread.currentThread().getPriority()); // 5
}
}
package p05;
import java.util.Date;
public class ThreadTest {
public static void main(String[] args) {
// 시간 출력
// 아래의 반복문은 메인 스레드에 의해 실행되고 있음
// 메인 스레드가 실행 단계로 가 while문 날짜를 구하고, try -catch 문을 만나 block 상태로 넘어가 1초 대기 하게 됨
// 출력 위와 같은 방식으로 반복 진행
// 시간 출력
while(true) {
Date d = new Date();
try {
//현재 실행중인 스레드를 block시킬때 사용됨.
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(d);
}
}
}