You will be fine

<Java> Future

by BFine
반응형

가. Future

 a. 무엇인가

  -  비동기 작업에 대한 결과라는 의미를 담고 있는 인터페이스로 비동기 작업을 기다리고 가져오고 , 완료 or 취소 되었는지 확인하거나 하는 기능을 한다.  

 

 b. 예제 만들기

public static void main(String[] args) throws InterruptedException, ExecutionException {

    ExecutorService executorService = Executors.newSingleThreadExecutor();

    Callable<String> callable = ()-> {
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.println("실행 " + Thread.currentThread());
        return "world";
    };

    Future<String> submit = executorService.submit(callable);

    for (int i = 0; i < 6; i++) {
        TimeUnit.MILLISECONDS.sleep(100);
        if(submit.isDone()){
            System.out.println("끝! " + Thread.currentThread());
            break;
        }else {
            System.out.println("처리중.. "  + Thread.currentThread());
        }
    }

    System.out.println(submit.get());
    
    executorService.shutdownNow();
}

  -  .isDone 을 활용해서 작업이 끝났는지 여부를 확인해보도록 만들어보았다. 비동기 작업이 callback 되어지기 전까지는 처리중으로 보여진다.

    => ExecuterSerivce 에 비동기 작업을 .submit 했을때 비동기 작업이 실행된다.

  -  위에서는 .get 이전에 완료되어 바로 출력이 되었지만 처리중이 였을경우 .get 에서는 블로킹이 발생한다.  

  -  그러면 이 Future 장점은 무엇인지 확인해보자

public static void main(String[] args) throws InterruptedException, ExecutionException {

    ExecutorService executorService = Executors.newSingleThreadExecutor();

    Callable<String> callable = ()-> {
        System.out.println("큰일 하는 중.. " + Thread.currentThread());
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.println("큰일 조금만 기다려줘.. " + Thread.currentThread());
        TimeUnit.MILLISECONDS.sleep(500);
        System.out.println("큰일 끝." + Thread.currentThread());
        return "world";
    };

    Future<String> submit = executorService.submit(callable);
    TimeUnit.MILLISECONDS.sleep(300);
    System.out.println("작은일 처리1 "+Thread.currentThread());

    TimeUnit.MILLISECONDS.sleep(200);
    System.out.println("작은일 처리2 "+Thread.currentThread());

    TimeUnit.MILLISECONDS.sleep(600);
    System.out.println("작은일 처리3 "+Thread.currentThread());

    String world = submit.get();
    System.out.println("hello " + world);

    executorService.shutdownNow();
}

  -  여기서 가장 중요한 부분은 비동기 작업의 결과를 Future를 통해 전달 받아 아래의 로직을 구현할 수 있는 부분 이다.

 

 c. 논블록킹

  -  어떤 작업이 진행되고 계산된 결과가 return 될때까지 기다리지 않고 바로 약속을 return 받는 것을 논블로킹이라고 한다. 

     => 예를들어 카페에서 주문을 하고 커피가 나올때까지 기다리는게 아니라 진동벨을 받는 것과 같다.  

  -  위의 디버깅 해보면 .submit 시점에 바로 완료되지 않는 FutureTask를 return 받는 것을 볼 수 있다.

 

 d. FutureTask

  -  FutureTask는 Runnable과 Future 인터페이스를 구현한 구현체 클래스이다.

  -  클래스를 살펴보면 6단계의 상태를 가지는 것을 할 수 있고 취소, Exception, 인터럽트 발생 시 에 대한 상태값도 가지고 있는 것을 볼 수 있다.

  -  .run 을 살펴보면 비동기 처리와 동일하게 ExecuterService에서 생성한 새로운 Thread에서 처리되고 있는 것을 볼 수있다.

 

 e. 블로킹

  -  .get 이 호출되면 블로킹이 발생한다고 위에 말했는데 어떻게 블로킹 처리를 하는지 궁금해졌다. 확인해보면

  -  state가 아직 NEW, COMPLETING 인 경우 .awitDone 으로 들어오고 내부를 살펴보면 무한 반복문을 볼 수 있다.

  -  그리고 COMPLETING 인 경우에는 Thread.yield를, NEW 인 경우에는 LockSupport.park 을 이용해서 블로킹 처리를 하고 있는 것을 알 수 있었다.

    => .yield는 우선순위가 같은 다른 Thread 에게 기회를 주기위해 현재 Thread를 대기상태로 만든다.

  -  LockSupport.park 했으니 LockSupport.unpark 하는 작업이 필요하다. 이부분은 .run 에서 비동기 작업이 끝났을 경우 .set 를 호출하며

     이안에 있는 .finishCompletion 에서 처리하고 있다.  

  

반응형

블로그의 정보

57개월 BackEnd

BFine

활동하기