JAVA/멀티스레딩
스레드 조정
최-코드
2024. 8. 28. 11:02
스레드 조정
- 하나의 스레드를 다른 스레드에서 종료시키는 작업이다.
- 왜 필요한가 - 스레드는 아무 것도 하지 않을 때에도 리소스를 차지한다.
- 언제 필요한가
- 스레드가 오작동할 때 -> 응답 없는 서버에 계속 요청 보내기와 같은 상황 or 허용한 시간보다 오래 동작되는 상황
- 애플리케이션을 종료하려고 할 때 -> main thread가 이미 종료되었다 하더라도 스레드가 남아 있다면 종료가 안 된다.
Thread.interrupt()
- 각 스레드 객체는 interrupt라는 메소드르 가진다.
- threadA에서 threadB.interrupt()를 하면 threadA에서 threadB에 인터럽트 신호를 보내게 된다.
- 이 신호는 스레드가 일시정지 상태(sleep)에 빠져있으면 바로 InterruptException을 발생시키지만, 일시정지가 아닌 상태에서는 아무 효과가 없다.
- 하지만 신호는 일단 스레드에 전달된 상태이므로 sleep없이 interrupt 신호를 확인할 수 있는 isInterupted() 메소드가 true를 반환하게 된다.
// interrupt 예시 1
public static void main(String[] args) {
Thread thread = new Thread(new BlockingTask());
thread.start();
thread.interrupt();
}
private static class BlockingTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500000);
} catch (InterruptedException e) {
System.out.println("Exiting blocking thread");
}
}
}
// interrupt 예시 2
public static void main(String[] args) {
Thread thread = new Thread(new LongComputationTask(new BigInteger("200000"), new BigInteger("10000000")));
thread.start();
thread.interrupt();
}
private static class LongComputationTask implements Runnable{
private BigInteger base;
private BigInteger power;
public LongComputationTask(BigInteger base, BigInteger power) {
this.base = base;
this.power = power;
}
@Override
public void run() {
System.out.println(base+"^"+power+"="+pow(base,power));
}
private BigInteger pow(BigInteger base, BigInteger power){
BigInteger result =BigInteger.ONE;
for(BigInteger i = BigInteger.ZERO; i.compareTo(power)!=0; i= i.add(BigInteger.ONE)){
if(Thread.currentThread().isInterrupted()){
System.out.println("Prematurely interrupted computation");
return BigInteger.ZERO;
}
result = result.multiply(base);
}
return result;
}
}
Daemon Thread
- 백그라운드에서 실행되는 스레드로 이 스레드가 실행되고 있어도 메인 스레드가 종료되면 애플리케이션 또한 종료된다.
- 앱의 주 작업이 아닌 백그라운드 작업을 맡길 때 사용한다.
- 예를 들어 텍스트 편집기에서 몇 분마다 작업을 파일레 저장하는 스레드가 있다. 이 때 우리는 앱을 닫고 싶을 때 백그라운드 스레드의 실행여부를 신경 쓰지 않고, 완료될 때까지도 기다리지 않는다.
public static void main(String[] args) {
Thread thread = new Thread(new LongComputationTask(new BigInteger("200000"), new BigInteger("10000000")));
thread.setDaemon(true);
thread.start();
thread.interrupt();
}
private static class LongComputationTask implements Runnable{
private BigInteger base;
private BigInteger power;
public LongComputationTask(BigInteger base, BigInteger power) {
this.base = base;
this.power = power;
}
@Override
public void run() {
System.out.println(base+"^"+power+"="+pow(base,power));
}
private BigInteger pow(BigInteger base, BigInteger power){
BigInteger result =BigInteger.ONE;
for(BigInteger i = BigInteger.ZERO; i.compareTo(power)!=0; i= i.add(BigInteger.ONE)){
result = result.multiply(base);
}
return result;
}
}
join()
- 스레드가 끝날 때까지 기다려주는 메소드이다.
- 특정 스레드 A에 대해 main스레드에서 threadA.join()와 같이 하면 threadA의 스레드가 종료될 때까지 join()을 호출한 라인에서 계속 기다리게 된다.
- join 메소드를 호출한 스레드는 블로킹 상태로 변하게 되는데, 스레드 스케줄링 대상이 되지 않으므로 cpu 시간을 갖지 않아 다른 연산 중인 스레드의 연산을 더욱 빨리 끝내줄 수 있다.
- 이 때 밀리초 인자를 주어서 스레드가 해당 밀리초를 넘도록 종료되지 않으면 이 메소드를 호출한 스레드가 실행 상태로 변하게 된다.
public static void main(String[] args) throws InterruptedException {
List<Long> inputNumbers = Arrays.asList(1000000000L, 3435L, 35435L, 2324L, 4656L, 23L, 2435L, 5566L);
List<FactorialThread> threads = new ArrayList<>();
for (Long inputNumber : inputNumbers) {
threads.add(new FactorialThread(inputNumber));
}
for (FactorialThread thread : threads) {
thread.setDaemon(true);
thread.start();
}
for (FactorialThread thread : threads) {
thread.join(1000);
}
for (int i = 0; i < inputNumbers.size(); i++) {
FactorialThread factorialThread = threads.get(i);
if (factorialThread.isFinished()) {
System.out.println("Factorial of " + inputNumbers.get(i) + " is " + factorialThread.getResult());
} else {
System.out.println("the calculation for " + inputNumbers.get(i) + " is still in progress");
}
}
}
public static class FactorialThread extends Thread {
private long inputNumber;
private BigInteger result = BigInteger.ONE;
private boolean isFinished = false;
public FactorialThread(long inputNumber) {
this.inputNumber = inputNumber;
}
@Override
public void run() {
this.result = factorial(inputNumber);
this.isFinished = true;
}
private BigInteger factorial(long n) {
BigInteger tempResult = BigInteger.ONE;
for (long i = n; i > 0; i--) {
tempResult = tempResult.multiply(new BigInteger(Long.toString(i)));
}
return tempResult;
}
public BigInteger getResult() {
return result;
}
public boolean isFinished() {
return isFinished;
}
}