2022년 10월 10일 월요일

Thread, Callable, Executor(framework) 쓰레드 다루기

Thread, Callable, Executor(framework) 쓰레드 다루기

Thread, Callable, Executor(framework) 쓰레드 다루기

최근 coroutine , rx 로 인해 쓰레드 체 관한 처리가 조금 쉬워지긴했다.

그래도 옛날 소스들을 보면 java thread, Executor 또는 AsyncTask를 이용해서 만들어진게 많다.

이중 주로 외부랑 httpd 통신할때 쓰면 Executor 에 대해 알아보자.

그전에 어차피 나올용어로서 Callable 과 Runnable을 알아보자


   static class MyCallable implements Callable<String> {

       @Override
       public String call() throws Exception {
           return "hehe";
       }
   }
   /* 사용 

ExecutorService mPool = Executors.newFixedThreadPool(5);

mPool.execute(new MyRunnable());
*/

   static class MyRunnable implements Runnable {

       @Override
       public void run(){
       }
   }
   /* 사용 

Future<String> mFuture = mPool.submit(new MyCallable());
try {
// 미래(future)에서 데이터가 오기까지 여기는 런타임 블럭처리된다.
Log.e("from Future", mFuture.get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
  • Callable : 보면 알겠지만 리턴값을 지정할수 있고 call() 로 실행한다. 또 에러처리를 할수 있어서 쓰레드실행시에 문제가 생겼을때 사용자가 적절한 처리를 할수있다.
  • Runnale : run으로 실행한다.

Executor Framework는 자바 1.5 부터 제공해주는 것으로 기존의 단순 Thread 를 프레임워크화 해서 좀덛 쓰레드를 유연하게 사용하도록 해 준다.

대표 기능으로 thread pool, 생명주기 관리, Task 관리, 병렬처리(?), 비동기(Future)처리지원 등이다.

아래는 Future를 사용한 비동기 처리 예제이다.

   static class MyCallable implements Callable<String> {
        CountDownLatch howMuchCounting;
        String s = "";

        @Override
        public String call() throws Exception {
            howMuchCounting.countDown();
            return "http://ohmy.god?" + s;
        }

        public void setS(String argS) {
            s = argS;
        }

        public void setCountDowner(CountDownLatch argHowMuchCounting) {
            howMuchCounting = argHowMuchCounting;
        }
    }

    private void runExe() {
        CountDownLatch howMuchCounting = new CountDownLatch(3);
        
        ExecutorService mPool = Executors.newFixedThreadPool(5);

        List<String> yourInputDatas = Arrays.asList("page=1", "page=2", "page=3");
        List<Future<String>> futures = new ArrayList<Future<String>>();
        for (final String dataItem : yourInputDatas) {
            MyCallable myCallable = new MyCallable();
            myCallable.setS(dataItem);
            myCallable.setCountDowner(howMuchCounting);
            futures.add(mPool.submit(myCallable));
        }

        // 바로 아래의 await로 쓰레드가 모두 실행될때까지 기다린다.
        try {
            howMuchCounting.await();
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        // 모두 끝났으면 셧다운
        mPool.shutdown();

        List<String> results = new ArrayList<String>();
        for (Future<String> future : futures) {
            // future에 있는 데이터는 그래도 사용 하기 번거로우니까 따로 담는다.
            try {
                results.add(future.get());
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for (String s : results) {
            Log.i("fure", s);
        }

    }
    /*
 fure: http://ohmy.god?page=1
 fure: http://ohmy.god?page=2
 fure: http://ohmy.god?page=3
 */

CountDownLatch 클래스는 동시성관련 유틸 클래스로서 초기에 몇개의 쓰레드가 동시에 이루질수 있는지 지정하고, 쓰레드의 각 처리가 끝나는 순간 하나씩 countDown하여 0 이 될때까지 await 함수를 통해 비동기작업이 끝나기를 기다리게 해준다.

이를 이용하여 모든 쓰레드를 강제로 닫는 shutdown 을 사용해도 문제가 없도록 구현할수 있게 해준다.

0 comments:

댓글 쓰기