스레드 상태
- NEW : 스레드가 생성되고 아직 start()가 호출되지 않은 상태
- RUNNABLE : 실행 중 또는 실행 가능한 상태
- BLOCKED : 동기화블럭에 의해서 일시정지(락이 풀릴 때까지 기다리는 상태)
- WAITING, TIMES_WAITING : 스레드의 작업이 종료되지는 않았지만 실행가능하지 않은 일시정지 상태. TIMED_WAITING은 일시정지 시간이 지정된 경우임.
- TERMINATED : 스레드의 작업이 종료된 상태
package kr.or.ddit.basic;
public class T10ThreadStateTest {
/*
* <스레드의 상태에 대하여...>
*
* - NEW : 스레드가 생성되고 아직 start()가 호출되지 않은 상태
* - RUNNABLE : 실행 중 또는 실행 가능한 상태
* - BLOCKED : 동기화블럭에 의해서 일시정지(락이 풀릴 때까지 기다리는 상태)
* - WAITING, TIMES_WAITING : 스레드의 작업이 종료되지는 않았지만 실행가능하지 않은 일시정지 상태
* TIMED_WAITING은 일시정지 시간이 지정된 경우임.
* - TERMINATED : 스레드의 작업이 종료된 상태
*/
public static void main(String[] args) {
TargetThread tTh = new TargetThread();
StatePrintThread spTh = new StatePrintThread(tTh);
spTh.start();
}
}
// 스레드의 상태를 출력하기 위한 스레드
class StatePrintThread extends Thread {
private Thread targetThread; // 상태를 모니터링할 대상 스레드
public StatePrintThread(Thread targetThread) {
this.targetThread = targetThread;
}
@Override
public void run() {
while(true) {
// 스레드의 상태값 확인하기
Thread.State state = targetThread.getState();
System.out.println("대상 스레드의 상태값 : " + state.name()); // NEW, RUNNABLE ...
// NEW 상태인지 검사
if(state == Thread.State.NEW) {
targetThread.start();
}
// 대상 스레드가 종료되었는지 검사
if(state == Thread.State.TERMINATED) {
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// Target용 스레드
class TargetThread extends Thread {
@Override
public void run() {
// RUNNABLE 상태
for(long i=1; i<=1000000000L; i++) {} // 시간 지연용
// TIMES_WAITING 상태
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// RUNNABLE 상태
for(long i=1; i<=1000000000L; i++) {} // 시간 지연용
}
}
스레드 예시
package kr.or.ddit.basic;
import java.util.ArrayList;
import java.util.List;
public class T11DisplayCharacterList {
/*
* 3개(명)의 스레드가 각각 알파벳 대문자를 출력하는데
* 출력을 끝낸 순서대로 결과를 나타내는 프로그램 작성하기
*/
public static void main(String[] args) {
List<DisplayCHaracter> disCharList = new ArrayList<DisplayCHaracter>();
disCharList.add(new DisplayCHaracter("홍길동"));
disCharList.add(new DisplayCHaracter("심청이"));
disCharList.add(new DisplayCHaracter("빨간모자"));
disCharList.add(new DisplayCHaracter("호랑이"));
for (Thread th : disCharList) {
th.start();
}
}
}
class DisplayCHaracter extends Thread {
private String name; // 스레드 이름
private int rank; // 순위
public DisplayCHaracter(String name) {
super(name); // super는 부모클래스의 생성자를 의미함, 이 과정을 통해서 스레드 이름을 정함
this.name = name;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
@Override
public void run() {
for(char ch='A'; ch<='Z'; ch++) {
System.out.println(name + "의 출력문자 : " + ch);
try {
Thread.sleep( (int)(Math.random()*301+200)); // 200 ~ 500 => 0.2초 0.5초 사이
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + " 출력 끝...");
}
}
=> 순위도 추가
package kr.or.ddit.basic;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class T11DisplayCharacterList {
/*
* 3개(명)의 스레드가 각각 알파벳 대문자를 출력하는데
* 출력을 끝낸 순서대로 결과를 나타내는 프로그램 작성하기
*/
static int CurrRank = 1; // 현재 순위 정보
public static void main(String[] args) {
List<DisplayCHaracter> disCharList = new ArrayList<DisplayCHaracter>();
disCharList.add(new DisplayCHaracter("홍길동"));
disCharList.add(new DisplayCHaracter("심청이"));
disCharList.add(new DisplayCHaracter("빨간모자"));
disCharList.add(new DisplayCHaracter("호랑이"));
for (Thread th : disCharList) {
th.start();
}
// 경기 끝난 후 순위를 출력하기 위해 기다림
for (Thread th : disCharList) {
try {
th.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Collections.sort(disCharList); // 정렬하기
System.out.println("경기 끝...");
System.out.println("---------------------------");
System.out.println("경 기 결 과");
System.out.println();
System.out.println("===========================");
System.out.println("순 위\t:\t이름");
System.out.println("---------------------------");
for (DisplayCHaracter dc : disCharList) {
System.out.println(dc.getRank() + "\t:\t" + dc.getName());
}
}
}
class DisplayCHaracter extends Thread implements Comparable<DisplayCHaracter>{
private String name; // 스레드 이름
private int rank; // 순위
public DisplayCHaracter(String name) {
super(name); // super는 부모클래스의 생성자를 의미함
this.name = name;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
@Override
public void run() {
for(char ch='A'; ch<='Z'; ch++) {
System.out.println(name + "의 출력문자 : " + ch);
try {
Thread.sleep( (int)(Math.random()*301+200)); // 200 ~ 500 => 0.2초 0.5초 사이
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setRank(T11DisplayCharacterList.CurrRank++);
System.out.println(name + " 출력 끝...");
}
// 순위
@Override
public int compareTo(DisplayCHaracter dc) {
return new Integer(getRank()).compareTo(dc.getRank());
}
}
yield() 메소드
1. 동등한 우선순위 이상의 다른 스레드에게 실행기회를 제공.(양보)
2. 스레드의 상태를 Runnable 상태로 바꿈. (실행 > 실행대기)
3. yield()메서드를 실행한다고 해서 곧바로 Runnable상태로 전이된다고 확신할 수 없음.
package kr.or.ddit.basic;
public class T12ThreadYieldTest {
/*
* yield() 메서드에 대하여...
*
* 1. 현재 실행 대기 중인 동등한 우선순위 이상의 다른 스레드에게 실행기회를 제공한다.(양보)
* 2. 현재 실행중인 스레드의 상태를 Runnable 상태로 바꾼다.
* 3. yield()메서드를 실행한다고 해서 현재 실행중인 스레드가 곧바로 Runnable상태로 전이된다고 확신할 수 없다.
*/
public static void main(String[] args) {
Thread th1 = new YieldHtreadEx1();
Thread th2 = new YieldHtreadEx2();
th1.start();
th2.start();
}
}
class YieldHtreadEx1 extends Thread {
public YieldHtreadEx1() {
super("양보 스레드");
}
@Override
public void run() {
for(int i=0; i<10; i++) {
// Thread.currentThread() : 현재 실행중인 스레드 객체를 리턴
System.out.println(Thread.currentThread().getName() + " : " + i);
for(int j=0; j<=1000000000; j++) {}
Thread.yield(); // 양보하기
}
}
}
class YieldHtreadEx2 extends Thread {
public YieldHtreadEx2() {
super("비양보 스레드");
}
@Override
public void run() {
for(int i=0; i<10; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
for(int j=0; j<=1000000000; j++) {}
}
}
}
스레드 종료
- 1. 메서드를 이용하지 않고 스레드 종료
package kr.or.ddit.basic;
public class T13ThreadStop {
public static void main(String[] args) {
ThreadStopEx1 th1 = new ThreadStopEx1();
th1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
th1.setStop(true); // 중지 시키기
}
}
class ThreadStopEx1 extends Thread {
private boolean stop;
public void setStop(boolean stop) {
this.stop = stop;
}
@Override
public void run() {
while(!stop) {
System.out.println("스레드 작업 중...");
}
System.out.println("자원 정리 중...");
System.out.println("실행 종료.");
}
}
- 2. stop() 메소드를 이용하여 스레드 종료
package kr.or.ddit.basic;
public class T13ThreadStop {
public static void main(String[] args) {
ThreadStopEx1 th1 = new ThreadStopEx1();
th1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
th1.stop(); // 중지 시키기
}
}
class ThreadStopEx1 extends Thread {
private boolean stop;
public void setStop(boolean stop) {
this.stop = stop;
}
@Override
public void run() {
while(!stop) {
System.out.println("스레드 작업 중...");
}
System.out.println("자원 정리 중...");
System.out.println("실행 종료.");
}
}
- 3. interrupt()메서드를 이용하여 스레드 종료
1. sleep()메서드나 join()메서드 등을 호출했을 때 interrupt()메서드를 호출하면 InterruptedException이 발생.
interrupt() : 인터럽트 걸기
package kr.or.ddit.basic;
public class T13ThreadStop {
public static void main(String[] args) {
ThreadStopEx2 th2 = new ThreadStopEx2();
th2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
th2.interrupt(); // 인터럽트 걸기
}
}
// interrupt()메서드를 이용하여 스레드를 멈추는 방법
class ThreadStopEx2 extends Thread {
@Override
public void run() {
// 방법1 => sleep()메서드나 join()메서드 등을 호출했을 때 interrupt()메서드를 호출하면
// InterruptedException이 발생한다.
try {
while (true) {
System.out.println("스레드 실행 중...");
Thread.sleep(1);
}
} catch (InterruptedException ex) {}
System.out.println("자원 정리 중...");
System.out.println("실행 종료.");
}
}
2. interrupt()메서드가 호출되었는지 검사
2-1. 스레드의 인스턴스 객체용 메서드를 이용하는 방법
isInterrupted() : 인터럽트가 걸리면 true
package kr.or.ddit.basic;
public class T13ThreadStop {
public static void main(String[] args) {
ThreadStopEx2 th2 = new ThreadStopEx2();
th2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
th2.interrupt(); // 인터럽트 걸기
}
}
// interrupt()메서드를 이용하여 스레드를 멈추는 방법
class ThreadStopEx2 extends Thread {
@Override
public void run() {
// 방법 2 => interrupt()메서드가 호출되었는지 검사하기
while(true) {
System.out.println("스레드 실행 중...");
// 검사 방법1 => 스레드의 인스턴스 객체용 메서드를 이용하는 방법
if(this.isInterrupted()) {
// isInterrupted() : interrupt가 걸렸으면 true
System.out.println("인스턴스 메서드 호출됨 : " + this.isInterrupted());
break;
}
}
System.out.println("자원 정리 중...");
System.out.println("실행 종료.");
}
}
2-2. 스레드의 정적메서드를 이용하는 방법
Thread.interrupted() : 처음 인터럽트가 걸리면 true가 되지만 곧 false로 바뀜. (static 변수)
package kr.or.ddit.basic;
public class T13ThreadStop {
public static void main(String[] args) {
ThreadStopEx2 th2 = new ThreadStopEx2();
th2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
th2.interrupt(); // 인터럽트 걸기
}
}
// interrupt()메서드를 이용하여 스레드를 멈추는 방법
class ThreadStopEx2 extends Thread {
@Override
public void run() {
// 방법 2 => interrupt()메서드가 호출되었는지 검사하기
while(true) {
System.out.println("스레드 실행 중...");
// 검사 방법2 => 스레드의 정적메서드를 이용하는 방법
if(Thread.interrupted()) {
System.out.println("정적 메서드 interrupted() 호출됨 : "
+ Thread.interrupted());
break;
}
}
System.out.println("자원 정리 중...");
System.out.println("실행 종료.");
}
}
데이터 공통 사용법
=> 스레드들이 공유 데이터를 이용하고 싶다면 공유 객체가 필요하다.
- 사용 방법
1. 공통 데이터 관리할 클래스 정의
2. 해당 클래스로 객체 생성
3. 각 스레드에 공유객체 제공
ex) 원주율을 계산하는 스레드가 있고, 계산된 원주율을 출력하는 스레드가 있다.
원주율을 계산한 후 이 값을 출력하는 프로그램을 작성하시오.
(이 때 원주율 데이터를 관리하기 위한 공유 객체가 필요하다.)
volatile를 사용해야 한다.
package kr.or.ddit.basic;
public class T14ThreadShareDataTest {
/*
* 스레드에서 데이터를 공통으로 사용하는 방법
*
* 1. 공통 데이터를 관리할 클래스를 정의한다.
* 2. 해당 클래스로 객체를 생성한다.
* 3. 각각의 스레드에 공유객체를 제공한다.
*
* 예) 원주율을 계산하는 스레드가 있고, 계산된 원주율을 출력하는 스레드가 있다.
* 원주율을 계산한 후 이 값을 출력하는 프로그램을 작성하시오.
* (이 때 원주율 데이터를 관리하기 위한 공유 객체가 필요하다.)
*/
public static void main(String[] args) {
ShareData sd = new ShareData();
CalcPIThread cTh = new CalcPIThread(sd);
PrintPIThread pTh = new PrintPIThread(sd);
cTh.start();
pTh.start();
}
}
// 원주율 데이터를 관리하기 위한 공유클래스 정의
class ShareData {
private double result; // 원주율 저장할 변수
// volatile가 없으면 값이 출력되지 않음
volatile private boolean isOk; //원주율 계산이 완료 되었는지 확인하기 위한 변수
/*
* volatile => 선언된 변수를 컴파일러의 최적화 대상에서 제외시킨다.
* 즉, 값이 변경되는 즉시 변수에 적용시킨다.
*/
public double getResult() {
return result;
}
public void setResult(double result) {
this.result = result;
}
public boolean isOk() {
return isOk;
}
public void setOk(boolean isOk) {
this.isOk = isOk;
}
}
// 원주율을 계산하기 위한 스레드
class CalcPIThread extends Thread {
private ShareData sd;
public CalcPIThread(ShareData sd) {
this.sd = sd;
}
@Override
public void run() {
/*
* 원주율 = (1/1 - 1/3 + 1/5 - 1/7 + 1/9 ......) * 4;
* 1 - 3 + 5 - 7 + 9 => 분모
* 0 1 2 3 4 => 2로 나눈 몫
*/
double sum = 0.0;
for(int i=1; i<=1500000000; i+=2) {
if( ((i/2) % 2) == 0 ) { // 2로 나눈 몫이 짝수이면..
sum += (1.0/i);
} else { // 2로 나눈 몫이 홀수이면..
sum -= (1.0/i);
}
}
sd.setResult(sum * 4); // 계산된 원주율값 설정함.
sd.setOk(true); // 계산이 완료되었음을 설정함.
}
}
// 계산된 원주율을 출력하기 위한 스레드
class PrintPIThread extends Thread {
private ShareData sd;
public PrintPIThread(ShareData sd) {
this.sd = sd;
}
@Override
public void run() {
while(true) {
if(sd.isOk()) {
break;
}
}
System.out.println();
System.out.println("계산된 원주율 : " + sd.getResult());
System.out.println(" PI : " + Math.PI);
}
}
package kr.or.ddit.basic;
public class T15SyncThreadTest {
public static void main(String[] args) {
ShareObject sObj = new ShareObject();
WorkThread wTh1 = new WorkThread(sObj, "첫번째");
WorkThread wTh2 = new WorkThread(sObj, "두번째");
wTh1.start();
wTh2.start();
}
}
// 공유객체용 클래스
class ShareObject {
private int sum = 0;
public void add() {
for(int i=0; i<1000000000; i++) {} // 동기화 전까지 시간벌기용
int n= sum;
n += 10;
sum = n;
System.out.println(Thread.currentThread().getName() + " 합 계 : " + sum);
}
}
// 작업용 스레드
class WorkThread extends Thread {
private ShareObject sObj;
public WorkThread(ShareObject sObj, String name) {
super(name);
this.sObj = sObj;
}
@Override
public void run() {
for(int i=1; i<=10; i++) {
sObj.add();
}
}
}
차례대로 출력되지 않기에 처리해줘야 함 => 동기화를 해줘야 한다.
'자바' 카테고리의 다른 글
[Java 고급] 10.5장 Test (1) | 2024.01.29 |
---|---|
[Java 고급] 11장 동기화, Lock 객체, Collection 클래스 동기화 처리, wait() & notify() (0) | 2024.01.29 |
[Java 고급] 9장 Process와 Thread 예시1 (1) | 2024.01.27 |
[Java 고급] 8장 Annotation (0) | 2024.01.27 |
[Java 고급] 7.5장 Test (0) | 2024.01.27 |