1.State
State는 Thread의 작업을 감시하는 역할을 한다.
스레드의 상태가 어떤지 지속적으로 알려주는 기능이다.
활용도는 낮은편..
package chap10.exam06.state;
public class WorkThread extends Thread {
@Override
public void run() {
for(long i=0; i<1000;i++) {
System.out.println(i);
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(long i=0; i<1000;i++) {
System.out.println(i);
}
}
}
package chap10.exam06.state;
public class Main {
private static Thread.State state;
public static void main(String[] args) throws InterruptedException {
/*워크 스레드 : 생성 -> 실행 -> 일시정지 -> 실행 -> 종료*/
/*메인스레드 : 워크스레드를 감시*/
WorkThread work = new WorkThread();
//메인 스레드는 지속적으로 워크 스레드를 감시
while(true) {
state = work.getState();
System.out.println("THREAD STATE : "+state);
//객체 생성시 워크 스레드 실행
if(state == Thread.State.NEW) {
work.start();
}
/*Runnable 이 순식간에 진행 되므로 잘 잡히지 않는다.
Sleep 을 제거 하면 볼수는 있다.
*/
Thread.sleep(500); //0.5초 휴식
if(state == Thread.State.TERMINATED) {
break;
}
}
}
}
2.Control(sleep, yield, join, wait, notify, stop, interrupt)
2-1 sleep, yield
sleep은 Thread를 대기 시키는 메소드로 안에 인자를 받는데 mil second로 1000값을 주면 1초동안 Thread를 대기 시킨다.
yield는 작업을 셀프 인터럽트 시키는 메소드로 작업을 다음 순서 스레드에게 양보한다고 이해하면 된다.
package chap10.exam07.yield;
public class ThreadA extends Thread {
boolean stop = false;
boolean yield = false;
@Override
public void run() {
while(!stop) {
System.out.println("Thread A 동작");
if(yield) {
System.out.println("Thread B 에게 양보");
Thread.yield();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread A 중지");
}
}
package chap10.exam07.yield;
public class ThreadB extends Thread {
boolean stop = false;
boolean yield = false;
@Override
public void run() {
while(!stop) {
System.out.println("Thread B 동작");
if(yield) {
System.out.println("Thread A 에게 양보");
Thread.yield();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread B 중지");
}
}
package chap10.exam07.yield;
public class MainThread {
public static void main(String[] args) throws InterruptedException {
/*
yield 는 자신이 쉬겠다는 의미가 아님
다른 스레드에게 할 수 있는 기회를 양보 하는 것
실행 순서 정도에 변화를 줄 수 있다.
*/
//A,B 스레드 생성 후 실행
ThreadA thA = new ThreadA();
ThreadB thB = new ThreadB();
thA.start();
thB.start();
//A 에게 양보 하라고 함(B 에게 우선권 양보)
thA.yield = true;
Thread.sleep(1000);
//B 에게 양보 하라고 함(A 에게 우선권 양보)
thB.yield = true;
Thread.sleep(1000);
//A,B 정지
thA.stop = true;
thB.stop = true;
}
}
2-2. join
스레드가 병렬로 처리 될 경우 작업 자체가 분리되는 부분이 있는데 join을 사용하면 작업이 공통 처리된다.
다음 예제는 메인 스레드와 oper 스레드가 join을 사용했을 때와
주석처리하여 사용하지 않았을 때의 결과를 비교하는 예제이다.
한번 직접 oper.join(); 을 주석처리하여 테스트 해보자.
package chap10.exam08.join;
public class OperThread extends Thread{
private int sum = 0;
@Override
public void run() {
for(int i=1; i<=100; i++) {
sum += i;
}
}
public int getSum() {
return sum;
}
}
package chap10.exam08.join;
public class MainThread {
public static void main(String[] args) throws InterruptedException {
//1~100 까지의 합
OperThread oper = new OperThread();
oper.start();//oper : 실제 계산 수행
oper.join();//oper 와 같이 가라, 이 줄을 주석처리 하여 테스트
//oper 의 수행 내용이 끝나고 나면 아래가 실행 된다.
//main : 계산 내용을 출력
System.out.println("1~100 의 합 : "+oper.getSum());
}
}
2-3. wait, notify
wait은 스레드를 대기상태로 만들고
notify는 스레드 중 하나를 실행대기 상태로 만들고
notifyall은 스레드 전체를 실행대기 상태로 만든다.
대기상태는 작업을 일시정지 하는것이고 실행대기는 작업 대기열에 넣어 연산을 준비하는 것이다.
package chap10.exam10.test;
public class CommonData {
private String data = null;
//wait(), notify() 등을 호출하기 위해서는 synchronized 필요
public synchronized void getData() {
try {
if(data != null) {//1. 데이터가 있으면 가져온다.
System.out.println("가져온 데이터 : "+this.data);
this.data = null;//가져왔으면 비워주고
}
notify(); //2. 깨우고
wait(); //3. 난 쉰다.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void setData(String data) {
try {
//1. 데이터가 없으면 만든다.
if(this.data == null) {
System.out.println("넣을 데이터 : "+data);
this.data = data;
}
notify(); //2. 넣고 나면 깨우고
wait(); //3. 난 쉰다.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package chap10.exam10.test;
public class Consumer extends Thread{
private CommonData data;
public Consumer(CommonData data) {
this.data = data;
}
@Override
public void run() {
for(int i=1; i<=5;i++) {
data.getData();
}
}
}
package chap10.exam10.test;
public class Producer extends Thread{
private CommonData data;
public Producer(CommonData data) {
this.data = data;
}
@Override
public void run() {
for(int i=1; i<=5;i++) {
data.setData("DATA_"+i);
}
}
}
package chap10.exam10.test;
public class Main {
public static void main(String[] args) throws InterruptedException {
CommonData data = new CommonData();
Producer pro = new Producer(data);
Consumer con = new Consumer(data);
pro.start();
Thread.sleep(10);
con.start();
}
}
2-4. stop, interrupt
stop과 interrupt는 Thread 작성 시 run에서 작업중인 내용일 종료시켜버린다.
Thread는 보통 while(true)를 통해서 무한루프를 돌려 감시체계를 만든다던가 특정 작업을 받기위해 대기하고 있다던가
그러한 경우로 자주 쓰이기 때문에 강제 종료해주는 기능이 필요할 때가 있다.
이때 stop() 을 사용 할 수 있으나 현재는 사용중지를 권고 하고 있다.
package chap10.exam11.stop;
public class Inter extends Thread {
@Override
public void run() {
/*
try {
while(true) {
System.out.println("Inter 실행 중");
Thread.sleep(1);
}
} catch (InterruptedException e) {
System.out.println("자원 정리");
System.out.println("종료");
}
*/
while(true) {
System.out.println("Inter 실행 중");
if(Thread.interrupted()) {
break;
}
}
System.out.println("자원 정리");
System.out.println("종료");
}
}
package chap10.exam11.stop;
public class StopFlag extends Thread {
private boolean stop = false;
public void setStop(boolean stop) {
this.stop = stop;
}
@Override
public void run() {
while(!stop) {
System.out.println("StopFlag 실행중");
}
System.out.println("자원 정리");
System.out.println("종료");
}
}
package chap10.exam11.stop;
public class MainThread {
public static void main(String[] args) throws InterruptedException {
/*Stop Flag 이용*/
StopFlag flag = new StopFlag();
flag.start();
Thread.sleep(1000);
flag.setStop(true);
/*강제 인터럽트 이용*/
Inter inter = new Inter();
inter.start();
Thread.sleep(1000);
inter.interrupt();//강제로 인터럽트 예외를 발생
}
}