2020-10-16 TIL

3 minute read

스레드풀

스레드풀

  • 스테이스리스는 요청이 들어와서 스레드를 만들 때마다 가비지가 생성된다.
    • 이 방식의 문제점을 해결하기 위한 것이 스레드 풀이다.
  • 스레드를 미리 만들어 놓고 사용하는 것
  • 프로그램의 성능 저하를 방지한다.
    • 매번 발생되는 작업을 병렬 처리하기 위해 스레드를 생성하고 수거하는데 따르는 부담이 프로그램의 전체적인 퍼포먼스를 저하시킬 수 있다.
    • 다수의 사용자의 요청을 수용하고 빠르게 처리하고 대응할 수 있다.
  • pooling 기법을 사용한다
    • = Flywieght 디자인 패턴
  • cross reference 문제 주의
    • MyThread와 MyThreadPool 이 상호 참조 관계일 때
    • 상호 참조를 하면 서로 변화가 있을 때마다 컴파일을 하기 때문에 무한 컴파일을 하게 된다.
    • 현재 컴파일러는 성능이 좋기 때문에 한번만 컴파일을 하지만 객체 지향에서는 사용하지 않는 것이 좋은 방식이다.
    • 이 문제점을 해결하기 위해서 ThreadPool을 만들어 MyThreadPool이 ThreadPool을 구현하도록 하고 MyThread는 ThreadPool을 사용하도록 한다.
    • 이렇게 하면 상호 참조 관계를 해소할 수 있다.
  • 자바로 만든 스레드는 전부 이 방식으로 돌아간다.
// 멀티 스레드 재사용 - Pooling 기법을 이용하여 생성된 객체를 재활용하기
package com.eomcs.concurrent.ex6;

import java.util.ArrayList;
import java.util.Scanner;

public class Exam0210 {

  static class MyThread extends Thread {
    ThreadPool pool;
    int count;

    public MyThread(String name, ThreadPool pool) {
      super(name);
      this.pool = pool;
    }

    public void setCount(int count) {
      // 객체에 줄 값을 설정
      this.count = count;
      synchronized (this) {
        // 객체에 알림을 주는 것
        notify();
      }
    }

    @Override
    public void run() {
      synchronized (this) {
        try {
          while (true) {
            // 작업하라는 알림이 올 때까지 기다린다.
            // not runnable 상태
            wait();

            // 알림이 오면 작업을 실행한다.
            for (int i = count; i > 0; i--) {
              System.out.printf("[%s] %d\n", getName(), i);
              Thread.sleep(2000);
            }

            // 작업이 끝났으면 스레드풀로 돌아간다.
            pool.add(this);
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
  }

  // 상호 참조 관계를 해소하기 위해서
  // 인터페이스를 준비했다.
  interface ThreadPool {
    Thread get();

    void add(Thread obj);
  }

  static class MyThreadPool implements ThreadPool {
    ArrayList<MyThread> list = new ArrayList<>();

    public MyThreadPool() {
      // 사용할 스레드 객체를 미리 생성한다.
      // - 나중에 MyThread가 Pool로 다시 리턴될 수 있도록
      //   스레드 객체를 생성할 때 Pool의 주소를 알려준다.
      MyThread t1 = new MyThread("1번 스레드=>", this);
      MyThread t2 = new MyThread("2번 스레드***>", this);
      MyThread t3 = new MyThread("3번 스레드-->", this);

      // 생성된 스레드를 컬렉션에 보관한다.
      t1.start();
      t2.start();
      t3.start();

      // 일단 무조건 스레드를 미리 실행해 놓는다.
      list.add(t1);
      list.add(t2);
      list.add(t3);
    }

    // 스레드 풀에서 한 개의 스레드를 꺼낸다.
    // 오버라이딩 할 때 하위 클래스로 바꾸는 것은 OK
    // 먹을것 중에 라면을 주는 것
    @Override
    public MyThread get() {
      if (list.size() > 0) { // 컬렉션에 남아있는 스레드가 있다면
        return list.remove(0);
      }
      return null; // 없으면 null을 리턴한다.
      // 현재 이 예제에서는 오직 3개의 스레드만 쓰도록 하였다.
    }

    // 스레드를 다 쓴 후에는 다시 스레드 풀에 돌려준다.
    @Override
    public void add(Thread t) {
      list.add((MyThread) t);
    }
  }

  public static void main(String[] args) {

    // 스레드풀 준비!
    MyThreadPool threadPool = new MyThreadPool();

    Scanner keyScan = new Scanner(System.in);

    while (true) {
      System.out.print("카운트? ");
      String str = keyScan.nextLine();
      if (str.equals("quit")) {
        break;
      }

      int count = Integer.parseInt(str);

      // 스레드풀에서 스레드를 한 개 꺼낸다.
      MyThread t = threadPool.get();
      if (t == null) {
        System.out.println("남는 스레드가 없습니다!");
        continue;
      }

      // 스레드의 카운트를 설정한다. 그러면 카운트를 시작할 것이다.
      t.setCount(count);
    }

    System.out.println("main 스레드 종료!");
    keyScan.close();
  }
}

이클립스에서 실행이 안될 때(Could not find of load)

  • 빈 파일에서 컴파일 된 것이 있는지 확인
  • 클린하고 재컴파일
  • 그레이들 클린이클립스
  • 그레이들 이클립스

시스템 개발

  • 요구사항 수집
    • 기존 시스템 분석 / 업무 분석
    • UI prototype 제작
  • 요구사항 분석
    • 1) who?
      • actor -> 시스템을 사용하는 사람 (예 : 은행원, 고객) / 프로세스 (예 : 타이머, 다른 시스템, ATM)
        • Primary Actor -> 시스템을 사용
        • Secondary Actor(Supplementery Actor) -> 시스템이 사용하는 외부 시스템
        • 회원 -> sns 통합 조회 앱 -> 유튜브, 구글지도(외부 시스템)
        • 회원이 primary, 외부 시스템이 secondary
      • actor diagram
        • Primary Actor
          • 사용자
            • 일반 회원
              • 카페지기
            • 관리자
          • 타이머
          • atm기기
        • Secondary Actor
          • 구글 지도
          • 네이버
          • 페이스북
          • 기상청
          • 다음 우편번호
      • 액터를 식별하는 것을 identify 한다고 한다.

Categories:

Updated: