package multi_thread.thread_stop_interrupt;
public class PrintThread1 extends Thread{
private boolean stop;
public void setStop(boolean stop) {
this.stop = stop;
}
public void run() {
while(!stop) {
System.out.println("실행 중");
}
System.out.println("자원 정리");
System.out.println("실행 종료");
}
}
package multi_thread.thread_stop_interrupt;
public class StopFlagExample {
public static void main(String[] args) {
PrintThread1 printThread = new PrintThread1();
printThread.start();
try { Thread.sleep(1000);} catch (InterruptedException e ) {}
printThread.setStop(true);
}
}
스레드를 종료시키는 법에는 2가지 방법이 있다. 하나는 stop()과 interrupt() 메소드를 이용하는 방법
하지만 stop()메소드는 스레드가 갑자기 종료되면 스레드가 사용 중이던 자원이 불안정 상태로 남겨지기 때문에
안 쓰이게 됩니다. 그래서 stop플래그를 이용한 방법이 있습니다.
stop플래그란 무한 반복문을 돌고 있을 때 boolean을 이용해 안정적으로 run()을 종료로 이끌게 하는 역할입니다.
package runnable_jar;
public class PrintThread extends Thread {
@Override
public void run() {
// 방법 1
// try {
// while (true) {
// System.out.println("실행 중");
// Thread.sleep(1); // sleep 있어야 main Thread에서 interrupt() 사용시 인식 함
// }
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// 방법 2
while(true) {
System.out.println("실행중");
if(Thread.interrupted()) { // sleep 없어도 사용 가능한 부분
break;
}
}
System.out.println("자원 정리");
System.out.println("실행 종료");
}
}
package runnable_jar;
public class InterruptExample {
public static void main(String[] args) {
Thread thread = new PrintThread();
thread.start();
try {
Thread.sleep(1000);
}catch(Exception e) {
e.printStackTrace();
}
// 일시 정지 상태일 때 InterruptedException을 발생 시킴
// 실행 대기 또는 실행 상태에서는 발생하지 않는다.
thread.interrupt();
}
}
interrupt 메소드는 스레드가 일시 정지일 때 InterruptedException 예외를 발생 시키는 역할을 합니다.
이것을 이용하면 run()메소드를 정상 종료시킬 수 있습니다.
지금 Thread.sleep(1)이라도 준 이유가 일시정지 일 때 예외를 발생시키기 때문입니다.
package multi_thread.thread_alternate;
public class WorkObject {
public synchronized void methodA() { // 동기화 메소드에서만 사용 가능 (synchronized)
System.out.println("ThreadA의 methodA() 작업 실행");
notify(); // wait() 상태 스레드를 실행 대기로 변경 (실행 가능한 상태)
try { wait(); } // 자기 자신 일시정지 상태로 변경
catch (InterruptedException e) { }
}
public synchronized void methodB() { // 동기화 메소드에서만 사용 가능 (synchronized)
System.out.println("ThreadB의 methodB() 작업 실행");
notify(); // wait() 상태 스레드를 실행 대기로 변경 (실행 가능한 상태)
try { wait(); } // 자기 자신 일시정지 상태로 변경
catch (InterruptedException e) { }
}
}
package multi_thread.thread_alternate;
public class ThreadA extends Thread{
private WorkObject workObject;
public ThreadA(WorkObject workObject) {
this.workObject = workObject;
}
@Override
public void run() {
for(int i = 0 ; i < 10; i++) {
workObject.methodA();
}
}
}
package multi_thread.thread_alternate;
public class ThreadB extends Thread{
private WorkObject workObject;
public ThreadB(WorkObject workObject) {
this.workObject = workObject;
}
@Override
public void run() {
for(int i = 0 ; i < 10; i++) {
workObject.methodB();
}
}
}
package multi_thread.thread_alternate;
public class WaitNotifyExample {
public static void main(String[] args) {
WorkObject sharedObject = new WorkObject();
ThreadA threadA = new ThreadA(sharedObject);
ThreadB threadB = new ThreadB(sharedObject);
threadA.start();
threadB.start();
}
}
두 개 스레드를 교대로 번갈아 실행 시키고 싶을 때notify()와 wait()를 이용하면 됩니다.
자신의 작업을 시작하면 상대방 스레드(B)를 실행대기 상태를 걸고 자신(A)은 실행합니다.
그 후 자신의 작업이 끝나면(A) 또 상대방 스레드(B)가 상대방(A)을 실행대기로 만들고 자기(B)는 실행합니다.
실행 끝난 후자신(B)을 일시정지 상태로 만들어야합니다.
공유객체는 각 작업 내용을 동기화 메소드로 구분해야합니다.
notify()같은 공유 객체의 동기화 메소드를 이용하는 상대방 스레드 실행대기상태로 만듭니다. wait()자신은 일시 정지 상태로 만듭니다.
package multi_thread.thread_join;
public class SumThread extends Thread{
private long sum;
public long getSum() {
return sum;
}
public void setSum(long sum) {
this.sum = sum;
}
public void run() {
for (int i = 1 ; i <= 100 ; i++) {
sum += i;
}
}
}
package multi_thread.thread_join;
public class JoinExample {
public static void main(String[] args) {
SumThread sumThread = new SumThread();
sumThread.start();
try {
sumThread.join();
// sumThread를 일시중지하는게 아니라 sumThread가 다 종료될 때까지
// 호출한 스레드(여기선 메인스레드)를 일시정지시킵니다.
}catch (InterruptedException e) {
}
System.out.println("1 ~ 100 합 : " + sumThread.getSum());
}
}
join이라는 메소드는 사용 스레드가 전부 끝날 때 까지 다른 스레드를 중지시키는 역할입니다.
스레드는 번갈아 실행 되기 때문에 메인 스레드를 멈추지 않으면 연산하기도 전에 Sum 값을 출력해버려 0이 나오게됩니다.