ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Multi-Thread Programming
    BackEnd/Java 2022. 1. 23. 03:13
    반응형

      Concurrent Software란 동시에 여러 작업을 할 수 있는 Software를 말합니다. Java에서 지원하는 Concurrent Progmming은 멀티프로세싱 (ProcessBuilder)과 멀티쓰레드가 있습니다.

     

    Multi-Thread Progmming 생성 방식

    1. Thread 상속

    public class MultiThread {
    
      public static void main(String[] args) {
        // 코드 상으로는 Thread-0 출력 이후 main이 출력되어야 하지만, 멀티쓰레드는 동시에 수행되기에 출력 순서를 보장하지 않습니다.
        MyThread myThread = new MyThread();
        myThread.start();
    
        System.out.println(Thread.currentThread().getName()); // [결과]: main
      }
    
      static class MyThread extends Thread {
        @Override
        public void run() {
          System.out.println(Thread.currentThread().getName()); // [결과]: Thread-0
        }
      }
    
    }

    2. Runnable 구현

    public class MultiThread {
    
      public static void main(String[] args) {
        // 코드 상으로는 Thread-0 출력 이후 main이 출력되어야 하지만, 멀티쓰레드는 동시에 수행되기에 출력 순서를 보장하지 않습니다.
        Thread thread = new Thread(() -> {
          System.out.println(Thread.currentThread().getName()); // [결과]: Thread-0
        });
        thread.start();
    
        System.out.println(Thread.currentThread().getName()); // [결과]: main
      }
    
    }

     

    Thread 주요 기능

    • sleep: 다른 쓰레드가 처리할 수 있도록 대기하지만 락을 잡고 있습니다. (Deadlock 발생 가능성 존재)
    • interrupt: interruptedException을 발생시켜 쓰레드를 깨웁니다.

      아래 코드는 thread가 3초 대기 후 종료되어야 하지만 main thread에서 interrupt를 발생시켜 1초 후 종료됩니다.

    public class MultiThread {
    
      public static void main(String[] args) throws InterruptedException {
        // 코드 상으로는 Thread-0 출력 이후 main이 출력되어야 하지만, 멀티쓰레드는 동시에 수행되기에 출력 순서를 보장하지 않습니다.
        Thread thread = new Thread(() -> {
          System.out.println(Thread.currentThread().getName()); // [결과]: Thread-0
          try {
            Thread.sleep(3000L); // 3초간 sleep
          } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return; // Exit
          }
        });
        thread.start();
    
        System.out.println(Thread.currentThread().getName()); // [결과]: main
        Thread.sleep(1000L); // 1초간 sleep
        thread.interrupt(); // thread의 interruptedException을 발생시킵니다.
      }
    
    }
    • join: 다른 쓰레드가 끝날 때까지 기다립니다.

      아래 코드에서 thread.join(); 생략 시 "Finished!"는 바로 출력되지만, thread.join(); 호출 시에는 thread 수행(3초)이 종료된 후 "Finished!"가 출력됩니다.

    public class MultiThread {
    
      public static void main(String[] args) throws InterruptedException {
        // 코드 상으로는 Thread-0 출력 이후 main이 출력되어야 하지만, 멀티쓰레드는 동시에 수행되기에 출력 순서를 보장하지 않습니다.
        Thread thread = new Thread(() -> {
          System.out.println(Thread.currentThread().getName()); // [결과]: Thread-0
          try {
            Thread.sleep(3000L); // 3초간 sleep
          } catch (InterruptedException e) {
            System.out.println("Interrupted!");
            return; // Exit
          }
        });
        thread.start();
    
        System.out.println(Thread.currentThread().getName()); // [결과]: main
    
        thread.join(); // thread가 끝날 때까지 기다립니다.
        System.out.println("Finished!");
      }
    
    }

     


     

    Executors

      High-Level Concurrency 프로그래밍으로 쓰레드를 만들고 관리하는 작업을 애플리케이션에서 분리하고, 그런 기능을 Executors에게 위임합니다. Executors는 애플리케이션이 사용할 쓰레드 풀을 만들고, 쓰레드 생명 주기를 관리합니다. 쓰레드로 실행할 작업을 제공할 수 있는 API를 제공합니다.

     

    주요 인터페이스

    • Executor: execute(Runnable)
    • ExecutorService: Executor 상속 받은 인터페이스로 Callable도 실행할 수 있으며, Executor를 종료시키거나 여러 Callable을 동시에 실행하는 등의 기능을 제공합니다.
    • ScheduledExecutorService: ExecutorService를 상속받은 인터페이스로 주기적으로 작업을 실행할 수 있습니다.
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class MultiThread {
    
      public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> System.out.println(Thread.currentThread().getName()));
        // [결과]: pool-1-thread-1
    
        // executorService는 프로세스가 죽지 않기 때문에 명시적으로 종료시켜 주어야 합니다.
        executorService.shutdown(); // 처리중인 작업 완료후 종료
        // executorService.shutdownNow(); // 즉시 종료
    
        ExecutorService fixedExecutorService = Executors.newFixedThreadPool(2);
        fixedExecutorService.submit(getRunnable());
        fixedExecutorService.submit(getRunnable());
        fixedExecutorService.submit(getRunnable());
        fixedExecutorService.shutdown();
        // [결과]: thread-1 과 thread-2 동시 처리
        // pool-2-thread-2
        // pool-2-thread-1
        // pool-2-thread-1
    
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        scheduledExecutorService.schedule(getRunnable(), 3, TimeUnit.SECONDS);
        scheduledExecutorService.shutdown();
        // 종료 없이 주기적으로 무한히 수행하는 방식입니다.
        // scheduledExecutorService.scheduleAtFixedRate(getRunnable(), 1, 2, TimeUnit.SECONDS);
      }
    
      private static Runnable getRunnable() {
        return () -> {
          System.out.println(Thread.currentThread().getName());
        };
      }
    
    }
    반응형

    'BackEnd > Java' 카테고리의 다른 글

    Java8. CompletableFuture  (0) 2022.01.23
    Callable과 Future  (0) 2022.01.23
    Java8. Date-Time API  (0) 2022.01.22
    Java8. Optional  (0) 2022.01.22
    Java8. 스트림 (Stream)  (0) 2022.01.22

    댓글

Designed by Tistory.