스레드 탱크 원리 상해

3576 단어
스레드 탱크 원리 상해

스레드 탱크 원리 상해


스레드 탱크는 병렬 프로그래밍에서 많이 사용된다. 스레드 탱크는 스레드 생성의 비용을 줄일 수 있고 연못화 자원을 만들 수 있다. 다음은 스레드 탱크의 원리에 대해 간단한 분석을 한다.

원본 코드 설명


우리는 스레드 풀을 사용하는데 가장 추천하는 방법은 수동으로 스레드 풀을 만드는 것이다. 코드는 다음과 같다.
private static final Executor WORK_THREAD = new ThreadPoolExecutor(10, 10, 
            0, TimeUnit.MINUTES,new LinkedBlockingDeque<>(1000));

이렇게 수동으로 스레드 탱크를 만드는 장점은 대기열의 크기를 제한하고 일부 파라미터에 대한 설정을 제한할 수 있다는 것이다. 다음은 구체적인 파라미터를 설명한다.
  • corePoolSize: 핵심 풀 크기는 주요 처리 작업의 스레드 풀 크기를 나타낸다. 첫 번째 10
  • 에 해당한다.
  • maxPoolsize: 스레드 탱크의 최대 스레드 수는 핵심 탱크가 가득 차고 막힌 대기열이 가득 차면 여분의 스레드로 추가 작업을 처리할 수 있음을 나타낸다. 두 번째 10에 대응한다.
  • TimeAlive: 비코어 풀 스레드가 유휴 상태에서 생존하는 시간
  • unit: TimeUnit.MINUTES
  • 막힌 대기열 크기, 마지막 매개 변수에 따라 수동으로 스레드 탱크를 만들면 무한한 막힌 대기열로 인한 OOM을 피할 수 있습니다.

  • 다음은 집행 과정을 설명하고 코드는 다음과 같다.
    /**
         * Executes the given task sometime in the future.  The task
         * may execute in a new thread or in an existing pooled thread.
         *
         * If the task cannot be submitted for execution, either because this
         * executor has been shutdown or because its capacity has been reached,
         * the task is handled by the current {@code RejectedExecutionHandler}.
         *
         * @param command the task to execute
         * @throws RejectedExecutionException at discretion of
         *         {@code RejectedExecutionHandler}, if the task
         *         cannot be accepted for execution
         * @throws NullPointerException if {@code command} is null
         */
        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            /*
             * Proceed in 3 steps:
             *
             * 1. If fewer than corePoolSize threads are running, try to
             * start a new thread with the given command as its first
             * task.  The call to addWorker atomically checks runState and
             * workerCount, and so prevents false alarms that would add
             * threads when it shouldn't, by returning false.
             *
             * 2. If a task can be successfully queued, then we still need
             * to double-check whether we should have added a thread
             * (because existing ones died since last checking) or that
             * the pool shut down since entry into this method. So we
             * recheck state and if necessary roll back the enqueuing if
             * stopped, or start a new thread if there are none.
             *
             * 3. If we cannot queue task, then we try to add a new
             * thread.  If it fails, we know we are shut down or saturated
             * and so reject the task.
             */
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);
        }
    

    위의 코드에 의하면 세 단계로 나뉘어져 있음을 알 수 있다
  • 초기화할 때 핵심 탱크 크기보다 적은 스레드는 핵심 스레드로 임무를 처리한다.
  • 코어 풀 스레드가 가득 차서 작업을 처리하면 작업이 차단 대기열에 들어갑니다
  • 막힌 대기열이 가득 차면 maxPoolsize의 라인으로 작업 처리
  • maxPoolSize의 라인이 가득 차면 작업을 거부합니다.

  • 또한 코드를 볼 때 매우 재미있는 현상을 발견했다. 즉, 원본 코드는 하나의 변수를 통해 스레드 탱크의 상태와 스레드 탱크의 현재 스레드 수를 유지하는 것이다.

    좋은 웹페이지 즐겨찾기