Skip to content

Latest commit

 

History

History
225 lines (148 loc) · 6.58 KB

s_3.md

File metadata and controls

225 lines (148 loc) · 6.58 KB

🚣‍♂️ 스레드 조정

스레드 종료

스레드를 종료해야 하는 이유

스레드는 아무것도 하지 않아도 리소스를 사용한다. ( Thread.sleep() )→ 메모리와 일부 커널 리소스

실행 중이라면 cpu 시간과 캐시공간도 사용.

따라서 생성한 스레드가 이미 작업을 완료 했다면 이 스레드가 사용하는 리소스를 정리해야한다.

또 스레드가 오작동 하거나, 애플리케이션 전체를 중단하기 위해서도 스레드를 종료한다.

메인 스레드가 종료 돼도 하나의 스레드라도 남아 있다면 애플리케이션은 종료 되지 않는다.


종료 메서드

Thread.interrupt

각 스레드 객체는 interrupt 라는 메서드를 가짐.

이것으로 인터럽트 신호를 보낼 수 있음.

  1. 인터럽트 당했을때 InterruptedException 을 발생 시키는 경우
private static class BlockingTask implements Runnable {

        @Override
        public void run() {
            //do things
            try {
				// 얘가 InterruptedException 발생
                Thread.sleep(500000);
            } catch (InterruptedException e) {
                System.out.println("Existing blocking thread");
            }
        }
    }

인터럽트가 발생하면 바로 잡아서 스레드를 종료.


  1. 인터럽트 신호를 명시적으로 처리하는 경우
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;
        }
    }

isInterrupted 메서드에서 'true'가 반환되면 이제 계산을 멈추고 스레드를 종료.


Daemon

thread.setDaemon(true);

해당 속성을 주면 메인 스레드가 종료 됨과 동시에 전체 앱 종료.

  1. 백그라운드 작업을 하고 싶을때.

스레드를 Daemon 으로 생성하며 보통 주작업이 아닌 백그라운드 작업을 맡음.

우리가 앱을 종료하고 싶을때 데몬 스레드 실행 여부는 신경 쓰지 않고 종료 할 수 있어야함.

  1. 작업 스레드에서 실행 되는 코드를 제어 할 수 없을때

외부 라이브러리를 사용하면 스레드 인터럽트 신호 처리 불가.

이때 스레드의 Daemon 속성을 true 로 주면 메인 스레드가 종료 됨과 동시에 전체 앱 종료




강의 제공 Quiz

Question 1:

다음 코드를 살펴보세요.

public static void main(String [] args) {
        Thread thread = new Thread(new WaitingForUserInput());
        thread.setName("InputWaitingThread");
        thread.start();
    }

    private static class WaitingForUserInput implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    char input = (char) System.in.read();
                    if(input == 'q') {
                        return;
                    }
                }
            } catch (IOException e) {
                System.out.println("An exception was caught " + e);
            };
        }
    }

애플리케이션을 프로그램적으로 중단할 수 있는 유일한 방법은?

스레드를 데몬으로 만드는 것. System.in.read()는 Thread.interrupt();에 응답하지 않음.

Question 2:

public static void main(String [] args) {
        Thread thread = new Thread(new SleepingThread());
        thread.start();
        thread.interrupt();
    }

    private static class SleepingThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000000);
                } catch (InterruptedException e) {
                }
            }
        }
    }

다음 중 올바른 문장을 선택하세요.

return 선언문을 catch 블록 안에 추가해서 애플리케이션을 중지해야 한다.

catch 블록을 빈 상태로 두어서는 안되며, InterruptedException catch 블록을 사용해서 (출력을 추가하거나 run 메서드에서 반환되기 전에 코드를 정리하는 방식으로) 현재 스레드를 효율적으로 중단하는 것이 좋습니다.






스레드 연결

여러 스레드가 실행 될때마다 다른 시나리오가 나온다. (누가 먼저 끝나는지 등등.) 우리는 스레드 실행 순서를 절대 알 수 없음.

만약 한 스레드가 다른 스레드에 의존하면? 스레드B 는 스레드A의 결과값이 필요하다.

  • 루프로 확인 하면?

그러면 루프로 확인하는데 cpu 리소스가 들어가 오히려 스레드A의 연산이 느려짐.

차리리 스레드B를 sleep 하고 비켜주는 편이 나음!


Thread.join()

race condition (경쟁 조건) - 두 개 이상의 스레드가 순서나 타이밍에 따라 공유 자원에 접근하는 상황, 누가 어떻게 먼저 접근 할 수 있을지 알 수 없다.

예시

  • 스레드A 는 스레드B의 계산 결과 변수 result 를 get 해와서 계산을 한다.
  • 이때 공유되는 자원은 계산 결과 변수 result.
  • 스레드A는 언제 스레드B가 계산을 다 끝내는지 알 수 없다.

Thread.join() 은 이럴때 사용!

Thread.join()을 하면 해당 스레드의 run() 코드가 다 실행 될때까지 기다린다.

예시케이스에서는 계산 결과 변수 result 동기화 가능.

하지만 이때 연산이 오래 걸리는 케이스가 있으면 무한정 기다림.

Thread.join(2000) 이때 이렇게 스레드 기다리는 시간을 정할 수 있음.

해당 2000ms 만 기다리고 넘어감.

한 스레드가 완료되는데 지나치게 오랜 시간이 걸리는 상황을 경계하자!


오늘의 exercise

ComplexCalculation