Java Thread 😏
스레드란 하나의 프로세스 안에서 독립적으로 실행되는 작업 단위를 뜻함
모든 프로세스에는 한 개 이상의 스레드가 존재하며 작업을 수행함
두개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스라고 함
※ 프로세스 : 실행중인 프로그램, 운영체제에 의해 메모리 공간을 할당 받아 동작중인 것을 뜻함
이런 프로세스는 프로그램에 사용되는 데이터, 메모리 등의 자원, 스레드로 구성됨
Thread의 생성주기 😊
Runnable 상태 :
스레드 실행 전 준비상태
Running 상태 :
스케줄러에 의해 선택된 스레드가 실행되는 단계
Blocked 상태 :
스레드가 작업을 완수하지 못하고 잠시 작업을 멈추는 단계
Thread의 생명주기 😶
Runnable (준비상태)
스레드 실행되기 위한 준비단계, CPU 미점유 중이고 실행하기 위해 대기하고 있는 상태
Running (실행상태)
CPU 점유하여 실행 중인 상태이고 run() 메서드는 JVM만이 호출 가능
준비상태의 여러 스레드 중 우선 순위 스레드 결정 될 시 JVM이 자동으로 run() 메서드 호출 -> 스레드가 Running 상태로 진입
Dead (종료상태)
실행상태에서 스레드가 모두 실행되고 난 후 완료 상태(done상태라고도 함)
Blocked (지연 상태)
CPU 점유권을 상실한 상태, 후에 특정 메서드 실행 시켜 준비상태로 전환,
wait() 메서드에 의해 Blocked 상태가 된 스레드는 nofity() 메서드 호출 될 시 준비상태로 감,
sleep(시간) 메서드에 의해 Blocked 상태가 된 스레드는 지정된 시간이 지나면 준비 상태로 감
Thread 생성/실행 😗
스레드 생성/실행 방법은 2가지가 있음
둘 다 run() 메소드에 작업할 내용을 작성하면 된다.
new Thread()로 객체 생성 후 start() 실행 시 내가 작성한 run()에 작성된 내용이 실행된다.
1.Thread class 상속
스레드 클래스를 상속 받을 경우 다른 클래스를 상속 받지 못하기에 일반적으로 Runnable 인터페이스를 구현하는 방법을 많이 사용함
// Thread class 직접 상속 예제
package java_test.dev.java;
public class Thread1 extends Thread {
private int[] cnt;
public Thread1(String threadname) {
super(threadname);
cnt = new int[10];
for (int start = 0; start < cnt.length; start++) {
cnt[start] = start;
}
}
// 스레드 작업 내용
public void run() {
for (int start : cnt) {
try {
// 1초 대기
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.out.println("스레드이름:" + currentThread().getName());
System.out.println("temp value :" + start);
}
}
// 메인 호출
public static void main(String[] args) {
Thread1 t1 = new Thread1("첫번째");
t1.start();
}
}
2.Runnable 인터페이스 구현
추상 메서드인 run() 1개만 가지고 있는 함수형 인터페이스이다.
// Runnable 인터페이스 구현 예제
package java_test.dev.java;
public class Thread2 implements Runnable {
private int[] temp;
public Thread2() {
temp = new int[10];
for (int start = 0; start < temp.length; start++) {
temp[start] = start;
}
}
// 스레드 작업 내용(Runnable 구현 시 강제 오버라이드)
@Override
public void run() {
for (int start : temp) {
try {
// 1초 대기
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.out.println("스레드이름:" + Thread.currentThread().getName());
System.out.println("temp value :" + start);
}
}
public static void main(String[] args) {
Thread2 t2 = new Thread2();
Thread t = new Thread(t2, "두번 째");
t.start();
}
}
멀티 스레드
여러 스레드를 동시에 실행시키는 기법
// 멀티 스레드 예제
package java_test.dev.java;
class ATM implements Runnable {
private long depositeMoney = 10000;
// 스레드에서 할 작업
public void run() {
// multi thread에서 데이터 공유
synchronized (this) {
for (int i = 0; i < 10; i++) {
// 준비상태로 변함
notify();
try {
// wait()으로 인해 blocked 상태로 변함
wait();
// 1초 대기
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 잔액이 없어지면 반복문 빠져나옴
if (getDepositeMoney() <= 0)
break;
withDraw(1000);
}
}
}
// 1000원씩 차감
public void withDraw(long howMuch) {
// 잔액이 있으면
if (getDepositeMoney() > 0) {
depositeMoney -= howMuch;
System.out.print(Thread.currentThread().getName() + " , ");
System.out.printf("잔액 : %,d 원 %n", getDepositeMoney());
} else {
System.out.print(Thread.currentThread().getName() + " , ");
System.out.println("잔액이 부족합니다.");
}
}
// 잔액 조회
public long getDepositeMoney() {
return depositeMoney;
}
}
public class MultiThread {
// main 실행
public static void main(String[] args) {
ATM atm = new ATM();
// multi thread 생성
Thread mother = new Thread(atm, "mother");
Thread son = new Thread(atm, "son");
// multi thread 실행
mother.start();
son.start();
}
}
synchronized 때문에 2개의 스레드에서 10,000원이 같이 사용된 걸 확인할 수 있음
Join(스레드 대기)
스레드는 보통 다른 스레드와 독립적으로 실행되지만 다른 스레드가 종료될 때까지 기다려야 되는 경우가 발생할 수 있음
ex) A스레드가 종료된 후 B 스레드가 실행되어야 될 경우
이 때 join() 사용
package java_test.dev.java;
class ThreadJoin implements Runnable{
@Override
// 스레드 구현
public void run() {
// TODO Auto-generated method stub
System.out.println("쓰레드1단계");
thread2();
}
public void thread2() {
System.out.println("쓰레드2단계");
thread3();
}
public void thread3() {
System.out.println("쓰레드3단계");
}
public static void main(String[] args) {
// main thread 시작 메시지 출력
System.out.println(Thread.currentThread().getName() + " start");
Runnable r = new ThreadJoin();
Thread thread = new Thread(r);
// 스레드 실행
thread.start();
// main thread 종료 메시지 출력
System.out.println(Thread.currentThread().getName() + " end");
System.out.println("===========================================================");
}
}
위 결과를 보면 main thread가 종료되고도 다른 스레드가 실행되는 걸 알 수 있다.
이를 스레드가 종료된 후 메인을 종료시키도록 변경하려면 아래처럼 변경하면 된다.
public static void main(String[] args) {
// main thread 시작 메시지 출력
System.out.println(Thread.currentThread().getName() + " start");
Runnable r = new ThreadJoin();
Thread thread = new Thread(r);
// 스레드 실행
thread.start();
// thread.join() 추가(예외처리 필수)
try {
// thread 종료까지 기다림
thread.join();
} catch (Exception e) {
// TODO: handle exception
}
// main thread 종료 메시지 출력
System.out.println(Thread.currentThread().getName() + " end");
System.out.println("===========================================================");
}
메인 시작 후 스레드 종료 후 메인이 종료된 걸 볼 수 있다.
참조 : 코딩팩토리님 블로그, 2018.12.17, https://coding-factory.tistory.com/279,
TCP School, http://www.tcpschool.com/java/java_thread_concept
코딩벌레님 블로그, https://dpdpwl.tistory.com/13
'IT > development' 카테고리의 다른 글
[apache/php] apache/php 로컬환경 세팅(apm, xampp 미사용) (0) | 2022.11.23 |
---|---|
[Java] java class version 확인(feat. unsupported major version..) (0) | 2022.11.23 |
[eclipse] preparing launch delegate(feat. tomcat 무한 starting) (0) | 2022.11.23 |
[eclipse] eclipse java comment template 설정 (0) | 2022.11.23 |
[spring] 의존성 주입 시 NPE(NullPointerException) (0) | 2022.11.23 |