Java 스레드 풀 사용(ThreadPoolExecutor 소개)

9642 단어
# 스레드 풀은 무엇입니까?스레드 탱크는 일종의 다중 스레드 처리 형식,java.util.concurrent.Executors는 java를 제공합니다.util.concurrent.Executor 인터페이스의 구현은 스레드 풀을 만드는 데 사용됩니다.서버가 작업을 완료하는 데 걸리는 시간은 T1 생성 시간, T2 작업 수행 시간, T3 제거 시간으로 가정합니다.T1 + T3가 T2보다 크면 스레드 풀을 사용하여 서버 성능을 향상시킬 수 있습니다.

스레드 풀 사용 방법#


ThreadPoolExecutor 소개


먼저 Thread Pool Executor의 계승 관계를 보십시오: Thread Pool Executor는 Abstract Executor Service를 계승합니다. 그 중에서 Abstract Executor Service는 Executor Service 인터페이스를 실현했고 Executor Service는 Executor 인터페이스를 계승했습니다.


Executor 인터페이스에는 리셋 방법 execute(Runnable command)가 하나만 있습니다.
public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}


인터페이스 Executor Service, 예를 들어 shutdown, 실시간으로 Excutor 실행을 닫을 수 있는 일련의 방법을 제공합니다.또한 Future 클래스를 통해 현재 작업 수행 상태를 판단할 수 있습니다.그리고 Submit 방법은 실행된 새로운 작업을 제출하는 데 사용되며, Future는 Excutor Service의 Submit 방법을 통해 되돌아옵니다.
추상류 Abstract Executor Service는 Executor Service의 일부 기능을 실현했다.예를 들어 submit ():
    /**
     * Returns a {@code RunnableFuture} for the given runnable and default
     * value.
     *
     * @param runnable the runnable task being wrapped
     * @param value the default value for the returned future
     * @param  the type of the given value
     * @return a {@code RunnableFuture} which, when run, will run the
     * underlying runnable and which, as a {@code Future}, will yield
     * the given value as its result and provide for cancellation of
     * the underlying task
     * @since 1.6
     */
    protected  RunnableFuture newTaskFor(Runnable runnable, T value) {
        return new FutureTask(runnable, value);
    }

    /**
     * Returns a {@code RunnableFuture} for the given callable task.
     *
     * @param callable the callable task being wrapped
     * @param  the type of the callable's result
     * @return a {@code RunnableFuture} which, when run, will call the
     * underlying callable and which, as a {@code Future}, will yield
     * the callable's result as its result and provide for
     * cancellation of the underlying task
     * @since 1.6
     */
    protected  RunnableFuture newTaskFor(Callable callable) {
        return new FutureTask(callable);
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public Future> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public  Future submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public  Future submit(Callable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

위의 반환 값이 FutureTask임을 알 수 있습니다.FutureTask는 Future 인터페이스를 간접적으로 구현합니다.중간에 Runnable 인터페이스가 있습니다.여기에서 그 기능을 아는 것은 말할 것도 없다.
마지막 라인 유지보수는 Thread Pool Executor 클래스에서 이루어집니다.다음은 ThreadPoolExecutor의 가장 핵심적인 구성 방법입니다.
매개변수 이름
작용
corePoolSize
코어 스레드 풀 크기
maximumPoolSize
최대 스레드 풀 크기
keepAliveTime
스레드 풀에서 코어PoolSize 수를 초과한 빈 스레드의 최대 생존 시간;allowCoreThreadTimeOut(true)으로 핵심 스레드의 유효 시간을 설정할 수 있음
TimeUnit
keepaliveTime 시간 단위
workQueue
작업 대기열 차단
threadFactory
새 라인 공장
RejectedExecutionHandler
제출 작업 수가 maxmumPoolSize+workQueue의 합을 초과하면 작업은 RejectedExecutionHandler에 맡기고 처리합니다
1. 스레드 풀이 코어PoolSize보다 작을 때, 새 제출 작업은 새 스레드 실행 작업을 만듭니다. 이때 스레드 풀에 빈 스레드가 존재하더라도.2. 스레드 풀이 corePoolSize에 도달하면 새 제출 작업은workQueue에 넣고 스레드 풀의 작업 스케줄링이 실행될 때까지 기다립니다.workQueue가 가득 차고 maximumPoolSize>corePoolSize가 되면 새 제출 작업은 새 라인을 만들어서 작업을 수행합니다. 4.제출 작업 수가 maximumPoolSize를 초과하면 새 제출 작업은 RejectedExecutionHandler가 처리합니다.스레드 풀에서 corePoolSize 스레드를 초과하고 유휴 시간이 keepaliveTime에 도달하면 유휴 스레드를 닫습니다. 6.allowCoreThreadTimeOut(true)을 설정하면 스레드 풀의 corePoolSize 스레드 유휴 시간이 keepaliveTime에 도달하면 닫힙니다.

스레드 풀의 몇 가지 일반적인 생성 방식: Executors가 제공하는 스레드 풀 구성 방안

  • 캐시 가능한 스레드 탱크를 만듭니다. 만약 스레드 탱크의 길이가 처리 수요를 초과하면 빈 스레드를 유연하게 회수할 수 있고, 회수할 수 없으면 새 스레드를 만듭니다.이 스레드 풀은 스레드 풀 크기를 제한하지 않습니다. 스레드 풀 크기는 운영체제(또는 JVM)가 생성할 수 있는 최대 스레드 크기에 전적으로 의존합니다
  • ExecutorService es = Executors.newCachedThreadPool();
    
  • 고정 수량의 스레드를 만드는 스레드 탱크: 스레드의 최대 병렬 수를 제어할 수 있으며, 초과된 스레드는 대기열에서 기다립니다.임무를 제출할 때마다 스레드가 스레드 탱크의 최대 크기에 도달할 때까지 스레드를 만듭니다.스레드 탱크의 크기가 최대치에 도달하면 변하지 않습니다. 만약 어떤 스레드가 실행 이상으로 끝난다면, 스레드 탱크는 새로운 스레드를 추가합니다..
  • ExecutorService es = Executors.newFixedThreadPool(2);
    
  • 단일 스레드의 스레드 풀을 만듭니다. 모든 작업이 지정된 순서(FIFO, LIFO, 우선순위)에 따라 실행될 수 있도록 유일한 작업 스레드로만 작업을 수행합니다.만약 이 유일한 라인이 이상하게 끝났다면, 그것을 대체할 새로운 라인이 있을 것이다.이 스레드 탱크는 모든 작업의 실행 순서가 작업의 제출 순서에 따라 실행될 것을 보장합니다
  • ExecutorService es = Executors.newSingleThreadExecutor();
    
  • 정시 라인 만들기: 정시 및 주기적 작업 수행 지원..
  • ScheduledExecutorService es = Executors.newScheduledThreadPool(2);
    

    ThreadPoolExecutor를 통해 스레드 풀 생성 ##


    상기 Executors는 공장 모드를 이용하여 우리에게 4가지 스레드 탱크 실현 방식을 제공했지만 사용을 추천하지 않습니다. 왜냐하면 Executors를 사용하여 스레드 탱크를 만드는 데 이 파라미터가 들어가지 않고 기본값을 사용하기 때문에 우리는 이 파라미터를 자주 무시합니다. 또한 기본적으로 사용하는 파라미터는 자원 낭비를 초래할 수 있기 때문에 바람직하지 않습니다.가장 좋은 것은ThreadPoolExecutor의 방식을 통해 이러한 처리 방식은 쓴 학생들이 스레드 탱크의 운행 규칙을 더욱 명확하게 하고 자원 소모의 위험을 피하도록 한다.
  • 버퍼 기능의 스레드 탱크를 구축하고 코어PoolSize=0, maximumPoolSize=Integer를 설정합니다.MAX_VALUE,keepaliveTime=60s, 그리고 용량이 없는 막힌 대기열 SynchronousQueue가 있기 때문에 작업이 제출되면 새로운 루틴을 만들 것입니다.스레드가 60s를 초과하면 제거됩니다:
  • ThreadPoolExecutor cachedThreadPool = new ThreadPoolExecutor(
                    0,
                    Integer.MAX_VALUE,
                    60L, TimeUnit.SECONDS,
                    new SynchronousQueue(),
                    new ThreadPoolExecutor.AbortPolicy());
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                }
            });
            cachedThreadPool.shutdown();
    
  • 고정 스레드 수 (2) 의 스레드 탱크를 구성합니다. 설정된 코어PoolSize는 maximumPoolSize와 크기가 같고 무계 LinkedBlockingQueue를 사용하여 차단 작업을 저장합니다. 따라서 나머지 작업은 더 이상 차단 대기열이 존재하며 Rejected ExecutionHandler가 처리하지 않습니다
  • ThreadPoolExecutor singleThreadPool = new ThreadPoolExecutor(
                2,
                2,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue(),
                new ThreadPoolExecutor.AbortPolicy());
        singleThreadPool.execute(new
    
        Runnable() {
            @Override
            public void run () {
            }
        });
        singleThreadPool.shutdown();
    
  • 하나의 스레드만 지원하는 스레드 탱크를 구축하고corePoolSize=maximumPoolSize=1, 무계 차단 대기열LinkedBlockingQueue를 설정한다.작업이 한 라인에서 직렬로 실행되는 것을 보증합니다
  • ThreadPoolExecutor singleThreadPool = new ThreadPoolExecutor(
                    1,
                    1,
                    0L,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue(),
                    new ThreadPoolExecutor.AbortPolicy());
            singleThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                }
            });
            singleThreadPool.shutdown();
    
  • 정시 기능이 있는 스레드 탱크를 구축하고corePoolSize를 설정하며 무계 지연 차단 대기열DelayedWorkQueue를 설정한다.재미있는 것은: maximumPoolSize=Integer.MAX_VALUE, DelayedWorkQueue는 무계 대기열이므로 이 값은 의미가 없습니다
  •         //  
            executorService1.schedule(new TimerTask() {
                @Override
                public void run() {
                    finish();
                    startActivity(new Intent(WelcomeUI.this, TabUI.class));
                }
            },1, TimeUnit.SECONDS);
            executorService1.shutdown();
    
            ScheduledExecutorService executorService2 = new ScheduledThreadPoolExecutor(1,new ThreadPoolExecutor.AbortPolicy());
            //  0 2 
            executorService2.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    finish();
                    startActivity(new Intent(WelcomeUI.this, TabUI.class));
                }
            },0, 2,TimeUnit.SECONDS);
            executorService2.shutdown();
    
            ScheduledExecutorService executorService3 = new ScheduledThreadPoolExecutor(1,new ThreadPoolExecutor.AbortPolicy());
            //  5 3 ( 8 , 3 , 3 )
            executorService3.scheduleWithFixedDelay (new TimerTask() {
                @Override
                public void run() {
                    finish();
                    startActivity(new Intent(WelcomeUI.this, TabUI.class));
                }
            },5, 3,TimeUnit.SECONDS);
            executorService3.shutdown();
    

    좋은 웹페이지 즐겨찾기