ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Thread] Runnable and Callable in Java
    ๊ฐœ๋ฐœ/Java 2022. 4. 25. 15:31

    Java ์ดˆ๊ธฐ๋ถ€ํ„ฐ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์€ ์–ธ์–ด์˜ ์ฃผ์š” ์ธก๋ฉด์ด์—ˆ๋‹ค. 

     

    Runnable ์€ ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ ์ž‘์—…์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์ œ๊ณต๋˜๋Š” ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ ,

    Callable ์€ Java 1.5์— ์ถ”๊ฐ€๋œRunnable์˜ ๊ฐœ์„ ๋œ ๋ฒ„์ „์ด๋‹ค.

     

    ๋‘ ์ธํ„ฐํŽ˜์ด์Šค ๋ชจ๋‘ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์„ ๋‚˜ํƒ€๋‚ด๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค. 

    ํ•˜์ง€๋งŒ, Runnable์€ Threadํด๋ž˜์Šค ๋˜๋Š”ExecutorService ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด Callable ์€ ํ›„์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋งŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๊ทธ๋Ÿผ ์ฐจ์ด์ ์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž.

     

    Runnable

    ๐Ÿ’ก๋ฐ˜ํ™˜ ๊ฐ’

    Runnable ์ธํ„ฐํŽ˜์ด์Šค ๋Š” ๊ธฐ๋Šฅ์  ์ธํ„ฐํŽ˜์ด์Šค์ด๋ฉฐ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๋‹จ์ผ run() ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค. ์Šค๋ ˆ๋“œ ์‹คํ–‰์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฐพ์ง€ ์•Š๋Š” ์ƒํ™ฉ์— ์ ํ•ฉํ•˜๋‹ค.

     

    ๐Ÿ’ก์‹คํ–‰ ๋ฐฉ์‹

    1) Thread ํด๋ž˜์Šค

    package e.thread;
    
    public class RunnableSample implements Runnable{
        @Override
        public void run() {
            System.out.println("This is RunnableSample's run() method.");
        }
    }

     

    package e.thread;
    
    public class RunThreads {
        public static void main(String[] args) {
            RunThreads threads = new RunThreads();
            threads.runBasic();
        }
    
        public void runBasic() {
            //Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ RunnableSample ํด๋ž˜์Šค๋ฅผ ์“ฐ๋ ˆ๋“œ๋กœ ๋ฐ”๋กœ ์‹œ์ž‘ํ•  ์ˆ˜๋Š” ์—†๋‹ค.
            //๋”ฐ๋ผ์„œ, ์ด์™€ ๊ฐ™์ด Thread ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์— ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์‹œ์ž‘ํ•ด์ฃผ์–ด์•ผ๋งŒ ํ•œ๋‹ค.
            RunnableSample runnable = new RunnableSample();
            new Thread(runnable).start();
    
        }
    }

    ๋จผ์ € run()์ด๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋Š” ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ˆ˜ํ–‰๋˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋งํ•˜๊ณ , start()๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋Š” ์“ฐ๋ ˆ๋“œ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋‹ค. 

     

    ์œ„์˜ ์ฝ”๋“œ์—์„œ์ฒ˜๋Ÿผ Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒฝ์šฐ์—๋Š” Thread ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž์— ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์‹œ์ž‘ํ•ด

    ์ฃผ๋ฉด ๋œ๋‹ค. 

     

    Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ์™€, Thread ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ๋น„๊ต ์ด์•ผ๊ธฐ๋Š” ์•„๋ž˜์˜ ๊ฒŒ์‹œ๊ธ€๋กœ ์ด๋™ํ•ด์„œ ๋ณด์ž.

     

    https://mong-dev.tistory.com/17
     

    [Thread] Thread๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ• - Runnable ์ธํ„ฐํŽ˜์ด์Šค์™€ Thread ํด๋ž˜์Šค์˜ ์ฐจ์ด

    ์•ˆ๋…•ํ•˜์„ธ์š”๐Ÿฟ๏ธ ์˜ค๋Š˜์€ ์“ฐ๋ ˆ๋“œ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ์ด์•ผ๊ธฐ๋ฅผ ๋‚˜๋ˆ ๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค. ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ํฌ๊ฒŒ ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” Runnable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ณ , ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š”

    mong-dev.tistory.com

     

     

    2) ExecutorService 

    public interface Runnable {
        public void run();
    }

     

    public class EventLoggingTask implements  Runnable{
        private Logger logger
          = LoggerFactory.getLogger(EventLoggingTask.class);
    
        @Override
        public void run() {
            logger.info("Message");
        }
    }
    public void executeTask() {
        // Executors์˜ ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์‹ฑ๊ธ€์“ฐ๋ ˆ๋“œ์ธ Executor๋ฅผ ์ƒ์„ฑํ•จ
        executorService = Executors.new SingleThreadExecutor();
        // executor์— Task ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ์ถœ(submit)ํ•ด์„œ ์‹คํ–‰์„ ์š”์ฒญํ•จ
        Future future = executorService.submit(new EventLoggingTask());
        // ์ข…๋ฃŒ
        executorService.shutdown();
    }

    ์ด ์˜ˆ์—์„œ ์Šค๋ ˆ๋“œ๋Š” ํ์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ๊ณ  ๋กœ๊ทธ ํŒŒ์ผ์— ๊ธฐ๋กํ•˜๋Š”๋ฐ, ์ž‘์—…์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ’์€ ์—†๋‹ค. ๋งˆ์ง€๋ง‰์˜ executeTask() ๋ฉ”์†Œ๋“œ์—์„œ ๋ณด๋“ฏ์ด ExecutorService๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ Future ๊ฐ์ฒด๋Š” ์–ด๋–ค ๊ฐ’๋„ ๋ณด์œ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

     

     

    Callable

    ๐Ÿ’ก๋ฐ˜ํ™˜ ๊ฐ’

    Callable ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ œ๋„ค๋ฆญ ๊ฐ’ V๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋‹จ์ผ call() ๋ฉ”์„œ๋“œ๋ฅผ ํฌํ•จ ํ•˜๋Š” ์ผ๋ฐ˜ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

     

    ๐Ÿ’ก์‹คํ–‰ ๋ฐฉ์‹

    1) Only ExecutorService 

    public interface Callable<V> {
        V call() throws Exception;
    }

     

    ์ˆซ์ž์˜ ๊ณ„์Šน์„ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ call()์— ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ๋ฉ”์„œ๋“œ ์„ ์–ธ๋ถ€์— throws๋กœ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์–ด์žˆ๋Š”๋ฐ, ์ด๋ถ€๋ถ„์€ ๋ฐ”๋กœ ๋‹ค์Œ ๋‹จ๋ฝ์—์„œ ์‚ดํŽด๋ณผ ์˜ˆ์ •์ด๋‹ˆ ์‹คํ–‰ ๋ฐฉ์‹๋งŒ ๋จผ์ € ๋ณด๋„๋ก ํ•œ๋‹ค.

    public class FactorialTask implements Callable<Integer> {
        int number;
    
        // standard constructors
    
        public Integer call() throws InvalidParamaterException {
            int fact = 1;
            // ...
            for(int count = number; count > 1; count--) {
                fact = fact * count;
            }
    
            return fact;
        }
    }
    @Test
    public void whenTaskSubmitted_ThenFutureResultObtained(){
        FactorialTask task = new FactorialTask(5);
        Future<Integer> future = executorService.submit(task);
     
        assertEquals(120, future.get().intValue());
    }

     

    ์•ž์„œ ๋งํ–ˆ๋“ฏ์ด, ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํฌ์ธํŠธ๋Š” call() ๋ฉ”์„œ๋“œ ์˜ ๊ฒฐ๊ณผ๋Š” Future ๊ฐ์ฒด ๋‚ด์—์„œ ๋ฐ˜ํ™˜์ด ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

     

     

    ๐Ÿ’ก์˜ˆ์™ธ์ฒ˜๋ฆฌ

    Runnable์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฉ”์„œ๋“œ ์„ ์–ธ์‹œ, "throws" ์ ˆ์ด ์ง€์ •๋˜์–ด ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€๋กœ ๊ฒ€์‚ฌ๋œ ์˜ˆ์™ธ๋ฅผ ์ „ํŒŒํ•  ๋ฐฉ๋ฒ•์ด ์—†๋Š”๋ฐ ๋ฐ˜ํ•ด, Callable์˜ call() ๋ฉ”์„œ๋“œ์—๋Š” "throws Exception" ์ ˆ์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ checked ์˜ˆ์™ธ๋ฅผ ๋” ์‰ฝ๊ฒŒ ์ „ํŒŒํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    โœ…call()์€ run()์ฒ˜๋Ÿผ ์˜ค๋ฒ„๋ผ์ด๋“œ ์‹œ ๊ตฌํ˜„๋ถ€์˜ ๋กœ์ง์„ ๊ฐœ๋ณ„ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด ์‹คํ–‰์‹œํ‚จ๋‹ค๋Š” ์ ์€ ๊ฐ™์ง€๋งŒ, ๋ฐ˜ํ™˜๊ฐ’์ด ์žˆ์–ด์•ผํ•˜๊ณ  ๋ฐ˜ํ™˜์— ์‹คํŒจํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์˜ˆ์™ธ๋ฅผ ๋ฏธ๋ฆฌ ์„ ์–ธํ•˜๋ฉด ์™ธ๋ถ€์—์„œ ํ˜ธ์ถœ ์‹œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ •์„ฑ์˜ ์ธก๋ฉด์—์„œ ํฐ ์žฅ์ ์ด๋‹ค.

     

     

    ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

    public class FactorialTask implements Callable<Integer> {
        // ...
        public Integer call() throws InvalidParamaterException {
    
            if(number < 0) {
                throw new InvalidParamaterException("Number should be positive");
            }
        // ...
        }
    }
    @Test(expected = ExecutionException.class)
    public void whenException_ThenCallableThrowsIt() {
     
        FactorialCallableTask task = new FactorialCallableTask(-5);
        Future<Integer> future = executorService.submit(task);
        Integer result = future.get().intValue();
    }

     

    ExecutorService๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Callable์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, Future.get()๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” Future๊ฐ์ฒด์— ์˜ˆ์™ธ๊ฐ€ ์ˆ˜์ง‘๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์›๋ž˜ ์˜ˆ์™ธ๋ฅผ ๋ž˜ํ•‘ ํ•˜๋Š” ExecutionException์ด ๋ฐœ์ƒํ•œ๋‹ค.

     

    ์œ„์˜ ํ…Œ์ŠคํŠธ์—์„œ ์œ ํšจํ•˜์ง€ ์•Š์€ ์ˆซ์ž๋ฅผ ์ „๋‹ฌํ•  ๋•Œ, ExecutionException์ด ๋ฐœ์ƒํ•œ๋‹ค. ์ด ์˜ˆ์™ธ ๊ฐ์ฒด์— ๋Œ€ํ•ด getCause() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ ํ•˜์—ฌ ์›๋ž˜ ํ™•์ธ๋œ ์˜ˆ์™ธ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

     

    Future ํด๋ž˜์Šค์˜ get() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด call ( )๋ฉ”์„œ๋“œ์—์„œ throw๋œ ์˜ˆ์™ธ๊ฐ€ ๋‹ค์‹œ ๋ณด๊ณ ๋˜์ง€ ์•Š๊ณ , ์ž‘์—…์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์™„๋ฃŒ๋œ ๊ฒƒ์œผ๋กœ ํ‘œ์‹œ๋œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋Š” get()๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์ด๋‹ค.

    @Test
    public void whenException_ThenCallableDoesntThrowsItIfGetIsNotCalled(){
        FactorialCallableTask task = new FactorialCallableTask(-5);
        Future<Integer> future = executorService.submit(task);
     
        assertEquals(false, future.isDone());
    }

    ์œ„์˜ ํ…Œ์ŠคํŠธ๋Š” FactorialCallableTask์— ๋Œ€ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์Œ์ˆ˜ ๊ฐ’์— ๋Œ€ํ•œ ์˜ˆ์™ธ๋ฅผ throwํ•˜๋”๋ผ๋„ ์„ฑ๊ณต์ ์œผ๋กœ ํ†ต๊ณผํ•œ๋‹ค.

     

     

     

    ์ •๋ฆฌ

      Runnable Callable
    ๋„์ž… JDK 1.0 JDK 1.5
    ํŒจํ‚ค์ง€ java.lang java.util.concurrent
    ๋ณด์œ  ๋ฉ”์„œ๋“œ run() call()
    ๋ฉ”์„œ๋“œ ๋ฐ˜ํ™˜๊ฐ’ ์—†์Œ ์žˆ์Œ
    ๋ฉ”์„œ๋“œ ์˜ˆ์™ธ ์„ ์–ธ ๋ถˆ๊ฐ€๋Šฅ ๊ฐ€๋Šฅ
    ์‹คํ–‰ ๋ฐฉ๋ฒ• Thread ๋˜๋Š” ExecutionService ExecutionService

     

    ๐Ÿ“—Reference

    - ์ž๋ฐ”์˜ ์‹ 
    - https://www.baeldung.com/java-runnable-callable
    - https://jvnlee.tistory.com/8

    ๋Œ“๊ธ€

Designed by Tistory.