多线程---线程池


参考博客1:http://www.cnblogs.com/exe19/p/5359885.html
参考博客2:http://www.jianshu.com/p/87bff5cc8d8c

1 . 线程池的体系结构

java.util.concurrent.Executor          [I]是一个顶层接口,在它里面只声明了一个方法void execute(Runnable command);
|-- ExecutorService                    [I]继承了Executor,线程池的主要接口
    |-- AbstractExecutorService        [A]抽象类,实现了ExecutorService中的大部分方法
        |-- ThreadPoolExecutor         [C]线程池的主要实现类
    |-- ScheduledExecutorService       [I]继承了ExecutorService,负责线程调度的接口
        |-- ScheduledThreadPoolExecutor[C]继承 ThreadPoolExecutor,实现 ScheduledExecutorService

 

2 .线程池的使用

public static void method1() {
        Executor pool = Executors.newFixedThreadPool(5);
        for(int i=0;i<5;i++){
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
1、Executors.newFixedThreadPool(5)初始化一个包含5个线程的线程池pool;
2、通过pool.execute方法提交1个任务,该任务打印当前的线程名;
3、负责执行任务的线程的生命周期都由Executor框架进行管理;

 

3 . ThreadPoolExecutor类

  • 构造方法
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

     

    • corePoolSize:线程池中的核心线程数。在创建了线程池后,默认情况下,线程池中的线程数为0即线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务 ( 除非调用了prestartAllCoreThreads()或者prestartCoreThread()这2个预创建线程的方法,这两个方法会在没有任务到来之前就创建corePoolSize个线程或者一个线程 )当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到阻塞缓存队列当中。
    • maximumPoolSize:线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;
    • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
    • unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
      TimeUnit.DAYS;              //天
      TimeUnit.HOURS;             //小时
      TimeUnit.MINUTES;           //分钟
      TimeUnit.SECONDS;           //秒
      TimeUnit.MILLISECONDS;      //毫秒
      TimeUnit.MICROSECONDS;      //微妙
      TimeUnit.NANOSECONDS;       //纳秒
    • workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
      1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
      2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
      3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
      4、priorityBlockingQuene:具有优先级的无界阻塞队列;
      其中ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
    • threadFactory:线程工厂,主要用来创建线程;
    • handler:线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:
      1、AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,默认策略;
      2、DiscardPolicy:也是丢弃任务,但是不抛出异常。
      3、DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
      4、CallerRunsPolicy:用调用者所在的线程来执行任务;
      当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
    • execute()方法

      public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            /*
             * Proceed in 3 steps:
             * 此过程分为3步:
             * 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.
             * 1.如果正在运行的线程数小于corePoolSize,则尝试启动一个新
             * 的线程来执行指定的任务。对addWorker 方法的调用会原子性
             * 的检查runState (运行状态)和workerCount(工作集数量 ),
             * 通过返回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.
             * 2. 如果一个线程可以成功加入队列,无论我们已经将线
             * 程添加进去了还是在进入这个方法时线程池已经关闭了都需
             * 要继续做两次检查(因为上次检查之后可能存在一个死掉的
             * 线程)所以就再次检查状态,并且如果必要就会滚加入队列的
             * 操作或者在一个也没有的时候启动一个新的线程。
             * 
             * 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);
        }

       

    • submit()方法
      此方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果

    • shutdown()和shutdownNow()方法
      这两个方法是用来关闭线程池的。

posted @ 2017-07-17 18:25  cello_ist  阅读(196)  评论(0编辑  收藏  举报