원칙과 스레드 풀 장면을 사용

도 1은 스레드 풀 설명 :
프로세서 유닛 내에서 다수의 실행 스레드의 주요 문제를 해결하기 위해 다중 스레딩 기술, 그것이 크게 프로세서 유닛의 처리량을 증가시키는, 프로세서 유닛의 대기 시간을 줄일 수있다.
작업을 완료하는 데 필요한 서버 시간을 가정입니다 : T1은 스레드 생성 시간, 시간 T2는 T3 스레드 시간을 파괴 스레드에서 작업을 수행 할 수 있습니다.

如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
            一个线程池包括以下四个基本组成部分:
            1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
            2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
            3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
            4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了

코드 복사
사본에는 코드
패키지 mine.util.thread을;

import java.util.LinkedList;  
import java.util.List;  

/** 
 * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息 
 */  
public final class ThreadPool {  
    // 线程池中默认线程的个数为5  
    private static int worker_num = 5;  
    // 工作线程  
    private WorkThread[] workThrads;  
    // 未处理的任务  
    private static volatile int finished_task = 0;  
    // 任务队列,作为一个缓冲,List线程不安全  
    private List<Runnable> taskQueue = new LinkedList<Runnable>();  
    private static ThreadPool threadPool;  

    // 创建具有默认线程个数的线程池  
    private ThreadPool() {  
        this(5);  
    }  

    // 创建线程池,worker_num为线程池中工作线程的个数  
    private ThreadPool(int worker_num) {  
        ThreadPool.worker_num = worker_num;  
        workThrads = new WorkThread[worker_num];  
        for (int i = 0; i < worker_num; i++) {  
            workThrads[i] = new WorkThread();  
            workThrads[i].start();// 开启线程池中的线程  
        }  
    }  

    // 单态模式,获得一个默认线程个数的线程池  
    public static ThreadPool getThreadPool() {  
        return getThreadPool(ThreadPool.worker_num);  
    }  

    // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数  
    // worker_num<=0创建默认的工作线程个数  
    public static ThreadPool getThreadPool(int worker_num1) {  
        if (worker_num1 <= 0)  
            worker_num1 = ThreadPool.worker_num;  
        if (threadPool == null)  
            threadPool = new ThreadPool(worker_num1);  
        return threadPool;  
    }  

    // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    public void execute(Runnable task) {  
        synchronized (taskQueue) {  
            taskQueue.add(task);  
            taskQueue.notify();  
        }  
    }  

    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    public void execute(Runnable[] task) {  
        synchronized (taskQueue) {  
            for (Runnable t : task)  
                taskQueue.add(t);  
            taskQueue.notify();  
        }  
    }  

    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    public void execute(List<Runnable> task) {  
        synchronized (taskQueue) {  
            for (Runnable t : task)  
                taskQueue.add(t);  
            taskQueue.notify();  
        }  
    }  

    // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁  
    public void destroy() {  
        while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧  
            try {  
                Thread.sleep(10);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
        // 工作线程停止工作,且置为null  
        for (int i = 0; i < worker_num; i++) {  
            workThrads[i].stopWorker();  
            workThrads[i] = null;  
        }  
        threadPool=null;  
        taskQueue.clear();// 清空任务队列  
    }  

    // 返回工作线程的个数  
    public int getWorkThreadNumber() {  
        return worker_num;  
    }  

    // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成  
    public int getFinishedTasknumber() {  
        return finished_task;  
    }  

    // 返回任务队列的长度,即还没处理的任务个数  
    public int getWaitTasknumber() {  
        return taskQueue.size();  
    }  

    // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数  
    @Override  
    public String toString() {  
        return "WorkThread number:" + worker_num + "  finished task number:"  
                + finished_task + "  wait task number:" + getWaitTasknumber();  
    }  

    /** 
     * 内部类,工作线程 
     */  
    private class WorkThread extends Thread {  
        // 该工作线程是否有效,用于结束该工作线程  
        private boolean isRunning = true;  

        /* 
         * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待 
         */  
        @Override  
        public void run() {  
            Runnable r = null;  
            while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了  
                synchronized (taskQueue) {  
                    while (isRunning && taskQueue.isEmpty()) {// 队列为空  
                        try {  
                            taskQueue.wait(20);  
                        } catch (InterruptedException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    if (!taskQueue.isEmpty())  
                        r = taskQueue.remove(0);// 取出任务  
                }  
                if (r != null) {  
                    r.run();// 执行任务  
                }  
                finished_task++;  
                r = null;  
            }  
        }  

        // 停止工作,让该线程自然执行完run方法,自然结束  
        public void stopWorker() {  
            isRunning = false;  
        }  
    }  
}  

코드 복사
복사합니다 코드를

코드 복사
사본에는 코드
패키지 mine.util.thread을;

//测试线程池  
public class TestThreadPool {  
    public static void main(String[] args) {  
        // 创建3个线程的线程池  
        ThreadPool t = ThreadPool.getThreadPool(3);  
        t.execute(new Runnable[] { new Task(), new Task(), new Task() });  
        t.execute(new Runnable[] { new Task(), new Task(), new Task() });  
        System.out.println(t);  
        t.destroy();// 所有线程都执行完成才destory  
        System.out.println(t);  
    }  

    // 任务类  
    static class Task implements Runnable {  
        private static volatile int i = 1;  

        @Override  
        public void run() {// 执行任务  
            System.out.println("任务 " + (i++) + " 完成");  
        }  
    }  
}  

코드를 복사
코드 복사
실행 결과를 :

WorkThread 수 : 3 완료된 태스크 번호 : 0 대기 태스크 번호 : 6
작업 1이 완료
완료 작업 2
작업 3을 완료
완료 작업 4를
완료 5 작업을
작업 완료 6
WorkThread 번호 : 3 작업 번호 완료 6 대기 태스크 수 : 0

분석 : 어떤 작업 인터페이스가 없기 때문에, 모든 작업 정의에서 전달 될 수 있으므로 스레드 풀 및 실제 작업이 완료되었는지 여부를 정확하게 확인할 수 없습니다 만, (이 작업을 수행하는 진정한 방법은이 작업이 완료 실행하는 것입니다) 작업이 실행되는 작업 대기열에서되었거나 완료되었음을 알 수 있습니다.

스레드 풀의 설명에 제공되는 2, 자바 클래스 라이브러리 :

 java提供的线程池更加强大,相信理解线程池的工作原理,看类库中的线程池就不会感到陌生了。

제 2 조 :

자바 스레드 풀 지침

간단한 소개
스레드를 사용하여 스레드 풀은 매우 가난에 매우 사용하기 전에 JDK1.4의 JDK 버전, 자바에서 매우 중요한 위치를 차지한다. JDK1.5 후이 상황이 크게 개선되었습니다. JDK1.5 후 java.util.concurrent의 패키지 가입이 패키지는 스레드와 스레드 풀에서 자바의 사용에 초점을 맞추고 있습니다. 우리가 개발 스레드 다루고있는 문제에 대한 매우 큰 도움을 제공합니다.

2 : 스레드 풀
스레드 풀 기능 :

스레드 풀 기능은 시스템에서 실행 스레드의 수를 제한하는 것입니다.
시스템의 환경에 따라 자동 또는 수동으로 최고의 영업 실적을 달성하기 위해 스레드의 수를 설정, 낭비의 시스템 자원, 시스템은 더 붐비는 비효율적 인 원인이된다. 스레드 풀 스레드의 수를 제어로, 다른 스레드 라인에서 기다리고. 작업은 작업을 완료 한 다음 큐가 시작의 정상에서 찍은된다. 더 큐 대기 처리, 대기의 스레드 풀 리소스가없는 경우. 새로운 작업을 실행할 필요가있을 때 대기하는 스레드 풀 작업자 스레드가있는 경우, 당신은 실행을 시작할 수 있습니다 그렇지 않으면 큐를 입력합니다.

왜 스레드 풀을 사용합니다 :

생성하고 스레드를 파괴 수를 줄이십시오 1. 각 작업자 스레드를 재사용 할 수 있으며, 여러 작업을 수행 할 수 있습니다.

서버가 각 스레드에 필요한 메모리의 약 1MB의 출력 (연소하면서 메모리의 과도한 소비를 방지하기 위해 2. 시스템의 용량, 스레드 풀 작업 라인의 스레드의 수를 조정할 수 있습니다, 스레드가 더 소비 엽니 다 더 큰 메모리, 마지막 충돌).

최상위 인터페이스 내부에 자바 스레드 풀 집행자하지만, 엄밀한 의미 executor 스레드 풀은 아니지만, 단지 실행 도구의 하나 개의 스레드. 실제 스레드 풀 인터페이스는 ExecutorService입니다이다.

더 중요한 카테고리 :

ExecutorService를

실제 스레드 풀 인터페이스를 제공합니다.

ScheduledExecutorService를

반복 필요 에너지 및 타이머 / TimerTask를 비슷한, 문제 해결 작업.

ThreadPoolExecutor입니다

ExecutorService를 기본 구현입니다.

로 스케줄

ScheduledExecutorService를 인터페이스 상속 ThreadPoolExecutor입니다,주기적인 작업 스케줄링 클래스의 구현입니다.

스레드 풀은 특히 스레드 풀의 원칙 아래를 들어, 더 복잡 구성하려면 매우 명확하지 않다, 스레드 풀의 가능성이 구성은 따라서 일반적으로 사용되는 일부 생성 일부 static 팩토리 실행자 클래스를 제공하고, 우수한 아니다 스레드 풀.

  1. newSingleThreadExecutor

단일 스레드 스레드 풀을 만들기. 이 모든 작업의 ​​단일 스레드 직렬 실행에 해당하는 경우에만 스레드 풀 스레드 작업입니다. 때문 만이 비정상 종료의 스레드 경우,이를 대체 할 새 스레드를있을 것입니다. 이 스레드 풀은 모든 작업의 ​​실행 순서는 작업 순서에 제출되도록합니다.

2.newFixedThreadPool

고정 크기의 스레드 풀을 만듭니다. 때마다 당신은 최대 크기에 도달하기 위해 스레드 풀 스레드 때까지 스레드를 생성하는 작업을 제출합니다. 스레드 풀의 크기에 도달하면 스레드 실행 비정상 종료하는 경우, 스레드 풀은 새 스레드를 추가 할 수 있기 때문에 최대는 변경되지 않습니다.

  1. newCachedThreadPool

캐시 된 스레드 풀을 작성합니다. 스레드 풀 스레드의 크기는 필요한 처리 작업을 초과하는 경우,

작업의 수,이 스레드 풀 지능적가 작업을 처리하기 위해 새 스레드를 추가 할 때 (60 초 작업을 수행하지 않습니다)는 부분적으로 무료로 회복 스레드 및. 이 스레드 풀 스레드 풀의 크기를 제한하지 않는 스레드 풀 스레드의 최대 크기는 만들 수 있습니다 운영 체제 (또는 JVM)의 크기에 전적으로 의존한다.

4.newScheduledThreadPool

스레드 풀의 크기에 제한을 만듭니다. 이 스레드 풀은 타이밍과 주기적으로 작업을 수행 할 필요가 지원합니다.

1 : newSingleThreadExecutor

MyThread.java

publicclassMyThread는 스레드를 {확장

@Override

publicvoid run() {

    System.out.println(Thread.currentThread().getName() + "正在执行。。。");

}

}

TestSingleThreadExecutor.java

publicclassTestSingleThreadExecutor {

publicstaticvoid main(String[] args) {

    //创建一个可重用固定线程数的线程池

    ExecutorService pool = Executors. newSingleThreadExecutor();

    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口

    Thread t1 = new MyThread();

    Thread t2 = new MyThread();

    Thread t3 = new MyThread();

    Thread t4 = new MyThread();

    Thread t5 = new MyThread();

    //将线程放入池中进行执行

    pool.execute(t1);

    pool.execute(t2);

    pool.execute(t3);

    pool.execute(t4);

    pool.execute(t5);

    //关闭线程池

    pool.shutdown();

}

}

산출

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

2newFixedThreadPool

TestFixedThreadPool.Java

publicclass TestFixedThreadPool {

publicstaticvoid main(String[] args) {

    //创建一个可重用固定线程数的线程池

    ExecutorService pool = Executors.newFixedThreadPool(2);

    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口

    Thread t1 = new MyThread();

    Thread t2 = new MyThread();

    Thread t3 = new MyThread();

    Thread t4 = new MyThread();

    Thread t5 = new MyThread();

    //将线程放入池中进行执行

    pool.execute(t1);

    pool.execute(t2);

    pool.execute(t3);

    pool.execute(t4);

    pool.execute(t5);

    //关闭线程池

    pool.shutdown();

}

}

산출

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 2 스레드가 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 2 스레드가 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

3 newCachedThreadPool

TestCachedThreadPool.java

publicclass TestCachedThreadPool {

publicstaticvoid main(String[] args) {

    //创建一个可重用固定线程数的线程池

    ExecutorService pool = Executors.newCachedThreadPool();

    //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口

    Thread t1 = new MyThread();

    Thread t2 = new MyThread();

    Thread t3 = new MyThread();

    Thread t4 = new MyThread();

    Thread t5 = new MyThread();

    //将线程放入池中进行执行

    pool.execute(t1);

    pool.execute(t2);

    pool.execute(t3);

    pool.execute(t4);

    pool.execute(t5);

    //关闭线程池

    pool.shutdown();

}

}

출력 :

풀 -1- 2 스레드가 실행되고있다. . .

풀 1 스레드 -4- 수행된다. . .

풀 -1- 스레드 3이 실행되고있다. . .

풀 -1- 쓰레드 1이 실행되고있다. . .

풀 -1- 스레드 5가 수행된다. . .

4newScheduledThreadPool

TestScheduledThreadPoolExecutor.java

publicclass TestScheduledThreadPoolExecutor {

publicstaticvoid main(String[] args) {

    ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);

    exec.scheduleAtFixedRate(new Runnable() {//每隔一段时间就触发异常

                  @Override

                  publicvoid run() {

                       //throw new RuntimeException();

                       System.out.println("================");

                  }

              }, 1000, 5000, TimeUnit.MILLISECONDS);

    exec.scheduleAtFixedRate(new Runnable() {//每隔一段时间打印系统时间,证明两者是互不影响的

                  @Override

                  publicvoid run() {

                       System.out.println(System.nanoTime());

                  }

              }, 1000, 2000, TimeUnit.MILLISECONDS);

}

}

산출

================

8384644549516

8386643829034

8388643830710

================

8390643851383

8392643879319

8400643939383

방법 3 : 상세 ThreadPoolExecutor에
서명 ThreadPoolExecutor에 완벽한 시공 방법은 다음에 ThreadPoolExecutor (INT corePoolSize를, INT maximumPoolSize를 긴 KeepaliveTime은, TimeUnit와 유닛의 BlockingQueue <Runnable를> Workqueue는, ThreadFactory를 ThreadFactory를, RejectedExecutionHandler 처리기).

corePoolSize를 - 스레드의 수는 유휴 스레드를 포함하여 풀에 유지합니다.

풀에서 허용되는 스레드의 MaximumPoolSize- 최대 수입니다.

이 KeepAliveTime는 - 스레드의 수가 코어보다 많은 경우,이 새 작업 긴 시간을 기다리고 초과 유휴 스레드 전에 종료됩니다.

단위 - 시간 단위이 KeepAliveTime 매개 변수를 설정합니다.

이 Workqueue - 작업을 수행하기 전에 큐를 유지합니다. 이 큐는 execute 메소드에 의해 제출 된 Runnable 작업을 보유하고 있습니다.

threadFactory - executor가 새로운 스레드를 생성 할 때 사용하는 팩토리.

처리기 - 처리 프로그램을 사용할 때 범위 큐 용량에서 스레드가 차단되기 때문이다.

ThreadPoolExecutor에 구현 클래스를 기본 실행자이다.

JDK 도움말 문서, 이러한 구절이있다 :

"강력 프로그래머를 사용하는 것이 좋습니다 더 편리 실행자 팩토리 메소드 Executors.newCachedThreadPool () (*** 스레드 풀 스레드가 자동으로 복구 할 수 있습니다), Executors.newFixedThreadPool (INT) (고정 사이즈의 thread 풀) Executors.newSingleThreadExecutor () (단일 백그라운드 스레드)

그들은 설정 미리 정의 된 대부분의 사용 시나리오입니다. "

여기에 몇 가지 종류의 어떤 소스는 다음과 같습니다

ExecutorService를 인 newFixedThreadPool (INT의 nThreads) : 고정 된 크기의 스레드 풀.

우리는 corePoolSize를 maximumPoolSize를하고 크기가,이 KeepAliveTime 어떤 테이블 이름과 단위의 값을 설정 (당신이 maximumPoolSize를 *** 큐 매개 변수가 의미가 단어를 사용하는 경우, 나중에 사실, 소개합니다) 동일하다 볼 수 있습니까? -이 살아 유지하고 싶지 달성! 마지막 BlockingQueue의이 LinkedBlockingQueue 등을 선택, 큐 특성을 가지고, 그는를 ***입니다.

  1. (nThreads INT) 공공 정적 ExecutorService입니다 인 newFixedThreadPool {

  2. , 사용해, 새로운 ThreadPoolExecutor (nThreads, nThreads을 반환

  3. 0L, TimeUnit.MILLISECONDS,

  4. 새로운에 LinkedBlockingQueue <Runnable를> ());

  5. }

ExecutorService를 newSingleThreadExecutor () : 단일 스레드

  1. 공공 정적 ExecutorService를 newSingleThreadExecutor () {

  2. 새로운 FinalizableDelegatedExecutorService을 반환

  3. (새로운 ThreadPoolExecutor에 (1, 1,

  4. 0L, TimeUnit.MILLISECONDS,

  5. 새로운에 LinkedBlockingQueue <Runnable를> ()));

  6. }

ExecutorService를 newCachedThreadPool는 () : *** 스레드 풀 스레드가 자동으로 복구 할 수 있습니다

이 구현은 흥미로운 것이다. *** 첫 번째는 스레드 풀, 그래서 우리는 maximumPoolSize를 큰 큰 찾을 수 있습니다. 둘째, BlockingQueue의 선택에에 SynchronousQueue의 사용. BlockingQueue를위한 몇 가지 이상한있을 수 있습니다, 단순히 : 큐는 각 삽입 작업은 다른 스레드에 의해 대응하는 삭제 오퍼레이션을 대기해야합니다.

  1. 공공 정적 ExecutorService를 newCachedThreadPool () {

  2. 0 (사용해, 새로운 ThreadPoolExecutor를 반환는 Integer.MAX_VALUE,

  3. 60L, TimeUnit.SECONDS,

  4. 새로운 SynchronousQueue는 <Runnable를> ());

    }
    시작 인터페이스 BlockingQueue는 <Runnable를>이로이 Workqueue 참조 시작합니다. JDK의에서, 사실, 우리는 큐의 세 가지 종류가 있습니다, 매우 명확하게 말했다.

모든 BlockingQueue를 전송하고 제출 된 작업을 보류 할 수 있습니다. 당신이 사용할 수있는이 큐는 풀 크기와 상호 작용 :

스레드가 corePoolSize를보다 적은 실행하는 경우, 집행 인은 항상 대기하지 않고 새 스레드를 첨가하는 것이 바람직. (현재 실행중인 스레드가 corePoolSize를보다 작은 경우, 작업을 저장 큐에 추가, 오히려 차오 Jiahuo (스레드를 직접하지 않을 것이다) 실행을 시작)

스레드 실행이 corePoolSize를 이상인 경우, 집행 인은 항상 오히려 새 스레드를 추가하는 대신, 큐에 가입을 요청하는 것이 바람직.

요청이 대기 할 수없는 경우, 새로운 스레드가 당신이 maximumPoolSize를 넘어이 스레드를 생성하지 않는 생성되고,이 경우, 작업이 거부됩니다.

큐의 세 가지 유형.

일반적으로 세 가지 큐잉 정책이 있습니다 :

직접 제출. 기본 옵션 작업 큐는 그들을 유지하지 않고 스레드 작업에 직접 제출됩니다, SynchronousQueue는 것입니다. 스레드가 작업을 실행하는 데 사용할 수있는 경우이 경우, 즉시 새로운 스레드를 구성합니다 때문에 실패 큐에 가입하려고의 다음 작업을 존재하지 않습니다. 이 전략은 내부 종속성을 가질 수있는 요청들을 처리 할 때, 로크가 발생 피한다. ***이의 maximumPoolSizes는 일반적으로 새로 제출 된 작업을 거부 피하기 위해 직접 제출해야합니다. 명령 대기열이 연속 도착의 평균 수보다 더 처리 할 수있는 경우,이 정책은 스레드 성장 가능성이 *** 수 있습니다.

*** 큐. (LinkedBlockingQueue 등은 예를 들어, 미리 정의 된 용량이 없음) *** 새로운 사용에 대한 모든 corePoolSize를 스레드가 사용중인 경우 대기열에서 대기 큐의 작업을 이끌 것입니다. 따라서, 스레드 생성 corePoolSize를 초과하지 않을 것이다. (따라서, 값 maximumPoolSize를도 유효하지 않습니다.) 각 작업이 완전히 각 작업 실행에 영향을 미치지 않는 다른 작업을 독립적으로 사용하기에 적합 할 때 *** 큐 예를 들어, 웹 페이지 서버. 이 라인은 명령 큐 ***이 전략은 스레드 성장의 가능성을 허용 연속 도착의 평균 개수보다 처리 할 때, 과도 버스트 요청을 처리하는 데 사용될 수있다.

경계 큐. 제한의 maximumPoolSizes를 사용하는 경우, 큐 (예 ArrayBlockingQueue 등과 같은) 리소스 소모를 방지하지만, 조정 및 제어하기 어려울 수있다 도움을 경계. 대기열의 크기 사이의 타협이 필요할 수 있습니다 최대 풀 크기 : 큰 큐와 작은 풀의 사용은 CPU 사용량, 운영 시스템 자원 및 오버 헤드 컨텍스트 스위칭을 최소화 할 수 있지만 이렇게하면 처리량이 감소 될 수 있습니다. 작업이 자주 차단 된 경우 (예를 들어,이 경우 I / O 경계), 시스템은 시간을 마련하려면 사용 권한보다 더 많은 스레드 수 있습니다. 작은 큐를 사용하면 일반적으로 더 큰 풀 크기, 높은 CPU 사용률이 필요하지만, 받아 들일 수없는 스케줄링 오버 헤드가 발생할 수 있습니다, 또한 처리량을 줄일 수 있습니다.

BlockingQueue의 선택.

예 1 : 직접 제출 정책, 즉 SynchronousQueue는.

먼저 SynchronousQueue는 그 작업의 수는 제한 없음,하지만 인해 특정 요소 후 큐 자체의 특성으로 제거 다른 스레드를 추가 한 후 기다릴 계속하기 위해 추가해야합니다 유지하는 능력이다, ***입니다. 여기에 핵심 스레드는 새로운 스레드를 생성되지만 동일한에서 우리는 다음과 같은 장면을 상상하지 않습니다.

우리는 다음과 같은 매개 변수 구조에 ThreadPoolExecutor를 사용합니다 :

  1. 사용해, 새로운 ThreadPoolExecutor (

  2. 2, 3, 30, TimeUnit.SECONDS,

  3. <Runnable를> 새로운 SynchronousQueue는 ()

  4. 새로운 RecorderThreadFactory ( "CookieRecorderPool"),

        new ThreadPoolExecutor.CallerRunsPolicy());  

    사용해, 새로운 ThreadPoolExecutor (

    2, 3, 30, TimeUnit.SECONDS,

    <Runnable를> 새로운 SynchronousQueue는 ()

    새로운 RecorderThreadFactory ( "CookieRecorderPool"),

    새로운 ThreadPoolExecutor.CallerRunsPolicy ());

    핵심은이 때 두 개의 스레드가 실행된다.

이 때, 이전에 설명에 따라 작업 (A)를 계속합니다 "와 같거나 corePoolSize를 항상 대기중인 요청을 선호하는 집행 인의 스레드보다 더 많은 경우 새 스레드를 추가하지 않고."A가 대기열에 추가되도록 한다.
다음은 작업 (B)를 제공하고, 코어 2 스레드 설명 자신의 일이 확인을 먼저 다음의 1에 시도 완료하지 않은,하지만 SynchronousQueue는 사용하기 때문에, 그들에 참여하지 않아야합니다.
이 시점에서 만족 상기 새 스레드를 만들 수밖에 없다 "요청이 대기 할 수없는 경우 maximumPoolSize를 넘어이 스레드를 생성하지 않는, 새로운 스레드가이 경우, 작업이 거부됩니다. 만들어집니다" 이 작업을 실행합니다.
이 세 가지 작업이 아직이 작업에 연속 완료하지 않은 경우 그러나 가능하지만, 첫번째 포스트 - 그것의 큐에 추가? 그것은 큐에 삽입하고, 스레드 수는 maximumPoolSize를 도달, 그래서 나는 비정상적인 전략을 수행했다 할 수 없습니다.
따라서, 보통은 *** maximumPoolSize를 따라서 상기 상황 (사용 된 경우 직접 원하는 대기열을 제한하는 경계) 발생 방지된다에 SynchronousQueue의 사용을 필요로한다. 매우 명확하게 작성 JDK에서 SynchronousQueue는 역할의 : 요청 세트를 처리하는 내부 종속성을 가질 수 있지만이 정책은 잠금을 피할 수 있습니다.

이것은 무엇을 의미합니까? 당신의 작업 A1 경우, A2가 서로 관계를, 당신이 실행되기 전에 A1 처음 A1에서 수행해야 SynchronousQueue는 우리가 보장 할 수있을 때, A1 후, A2를 제출, 제출 A1을 실행할 필요가있다, A2는 추가 할 수 없습니다 큐이다.

예 2 : *** 큐 정책, 즉 LinkedBlockingQueue 등

앞서 언급 한 규칙에 따라,이 인 newFixedThreadPool을 가지고 :

스레드가 corePoolSize를보다 적은 실행하는 경우, 집행 인은 항상 대기하지 않고 새 스레드를 첨가하는 것이 바람직. 작업이 계속 증가 때, 다음 무슨 일이 일어날 것인가?

스레드 실행이 corePoolSize를 이상인 경우, 집행 인은 항상 오히려 새 스레드를 추가하는 대신, 큐에 가입을 요청하는 것이 바람직. 확인 작업이 대기열에 가입하게이 시간, 다음 경우는 새로운 스레드를 추가 할 것인가?

요청이 대기 할 수없는 경우, 새로운 스레드가 당신이 maximumPoolSize를 넘어이 스레드를 생성하지 않는 생성되고,이 경우, 작업이 거부됩니다. 이 흥미 여기서, 큐를 가입 할 수없는이있을 수있다? *** 대기열에 대해, 자신의 특성을 가지고 SynchronousQueue는 달리, 항상 (물론, 또 다른 문제를 자원 고갈)을 추가 할 수 있습니다. 새 스레드를 트리거하지 않습니다 다른 단어! 스레드 수의 corePoolSize를 크기는 항상 그 실행을 시작 대기열에서 작업을했다, 현재 바쁜를 실행합니다. 그래서 이러한 장기 실행 작업의 구현으로 급증 작업을 방지하고, 시간 처리 작업보다 훨씬 빠르게 작업을 추가 할뿐만 아니라, 성장하는, 곧 버스트.

실시 예 3 : ArrayBlockingQueue를 사용 경계 큐.

또한 어떤 진리를 JDK를 사용하는 것은 권장하지 않습니다, 가장 사용하기 복잡하다. 위의과 비교했을 때, 가장 큰 특징은 자원 고갈이 발생되지 않도록하는 것입니다.

예를 들어, 다음과 같은 구성 방법을 참조하십시오

  1. 사용해, 새로운 ThreadPoolExecutor (

  2. 2, 4, 30, TimeUnit.SECONDS,

  3. <Runnable를> 새로운 ArrayBlockingQueue 등 (2)

  4. 새로운 RecorderThreadFactory ( "CookieRecorderPool"),

  5. 새로운 ThreadPoolExecutor.CallerRunsPolicy ());

사용해, 새로운 ThreadPoolExecutor (

2, 4, 30, TimeUnit.SECONDS,

new ArrayBlockingQueue<Runnable>(2),

new RecorderThreadFactory("CookieRecorderPool"),

new ThreadPoolExecutor.CallerRunsPolicy());

모든 작업이 실행되지 않습니다 가정합니다.

는 C, D, 그들은이 큐에 배치 될 경우 다음 E 돌아올 경우의 초림의 경우, B는, 다음, 직접 실행, F는, 다음, F.을 스레드 실행 E를 증가 그러나 다시 작업하는 경우, 큐는 스레드의 수가 최대 한계에 도달 한 받아 들일 수 없다, 그래서 그것을 처리하는 전략을 사용하지 않습니다.

이 KeepAliveTime

JDK의 설명입니다 : 스레드의 수가 코어보다 많은 경우,이 작업이 유휴 스레드가 최대 시간 전에 종료 새로운 과잉을 기다리고 있습니다.

길기도의 비트는, 사실,이 응용 프로그램의 "풀"의 사용은, 그들의 대부분은 비슷한 매개 변수를 구성 할 필요가 있고, 이해하기 어렵지 않다. 이러한 데이터베이스 연결 풀, maxIdle에서 DBCP, minIdle 매개 변수로.

이것은 무엇을 의미합니까? 위의 설명에 따라, 나중에 "뭔가 빌려도있다", 속담, 항상 "빌린"된 노동자의 소유자에게 보냈지 만 여기에 문제는 그것이 무엇을 빌린 근로자 그냥 완료하면 작업에 관해서 돌아 가야하지만, 나중에뿐만 아니라 작업을 발견, 그것은 빌려해야하지 않을까요? 갈이, 상사가 확실히 큰 머리이다이 방법은 죽었다.

합리적인 전략 : 그것은 빌린 때문에,이 순간보다 더 걸릴 것이다. 시간 "일정 기간이"더 이상이 근로자보다 적은 찾을 때까지, 우리는 돌아갈 수 없다. 여기에 일정 기간이 KeepAliveTime 의미,이 KeepAliveTime 값을 측정하는 TimeUnit와입니다.

RejectedExecutionHandler

또 다른 경우는, 다음 양 팀 모두 수락을 거부했다 보스에 빌려 노동자,하지만 작업이 아직 오지, 또는 바쁜 계속하더라도 때문이다.

RejectedExecutionHandler 인터페이스는 거부 작업 치료의 방법을 사용자 정의 할 수있는 기회를 제공한다. 소스 코드는 매우 간단하기 때문에 가능한 ThreadPoolExecutor에서 이미 기본 4 전략으로 포함, 간단는 여기 기록했다.

CallerRunsPolicy은 : 실행 스레드 호출은 작업 자체를 실행합니다. 이 정책은 속도가 새 작업을 제출 느려질 수, 간단한 피드백 제어 메커니즘을 제공합니다.

  1. 공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

  2. 만약 (! e.isShutdown ()) {

  3. r.run ();

  4. }

  5. }

공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

       if (!e.isShutdown()) {

           r.run();

       }

   }

이 전략은 분명히 임무를 포기하고 싶지 않았다. 수영장 더 자원이 없기 때문에 그러나, 다음 직접 자신을 실행하기 위해 실행 스레드를 호출합니다.

AbortPolicy : 핸들러는 실행시 RejectedExecutionException를 던져 거부

  1. 공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

  2. ) (새 RejectedExecutionException를 던져;

  3. }

공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

       throw new RejectedExecutionException();

   }

이 전략은 직접 던져 버리는 작업이다.

DiscardPolicy : 작업을 수행 할 수 없습니다가 삭제됩니다

  1. 공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

  2. }

공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

   }

이 전략과 AbortPolicy 거의 같은, 작업이 삭제됩니다,하지만 그는 예외가 발생하지 않습니다.

의 DiscardOldestPolicy : 프로그램의 실행이 종료되지 않은 경우 삭제됩니다 임무 작업 큐의 선두에 위치, 다음 (다시 실패 할 경우,이 절차를 반복) 프로그램의 실행을 다시 시도

  1. 공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

  2. 만약 (! e.isShutdown ()) {

  3. e.getQueue () 설문 조사 ().;

  4. e.execute (R);

  5. }

    }  

    공공 무효 rejectedExecution (Runnable를 R, ThreadPoolExecutor에 전자) {

       if (!e.isShutdown()) {
    
           e.getQueue().poll();
    
           e.execute(r);
    
       }

    }

이 정책은 약간 더 복잡 전제를 닫지 않은 풀의 큐 캐시 초기 작업에서 손실보다도 먼저, 그리고 다음 작업을 실행하려고합니다. 이 전략은 적절한 치료가 필요합니다.

아이디어 : 다른 스레드가 여전히 실행중인 경우, 다음 작업에 새 작업이 큐에 캐시 이전 쫓겨, 큐 다시 작업 가장 오래된 작업을 시작된다.

요약 :

이 KeepAliveTime maximumPoolSize를 입력하고 BlockingQueue와 밀접한 관계가있다. BlockingQueue의이 *** 경우, maximumPoolSize를이, 자연이 KeepAliveTime이 아무 의미가 없을 것이다 발사하지 다음 않았다.

핵심 수가 적을 경우 작업은 자주, 시스템이 자주 응용 프로그램 스레드를 복구 할 경우이 KeepAliveTime하고, 작은을 설정하면서 반대로, BlockingQueue의 값과 작은을 경계.

(nThreads INT) 공공 정적 ExecutorService입니다 인 newFixedThreadPool {

   return new ThreadPoolExecutor(nThreads, nThreads,

                                 0L, TimeUnit.MILLISECONDS,

                                 new LinkedBlockingQueue<Runnable>());

}

추천

출처blog.51cto.com/9527824/2435706