Contents
  1. 1. 参考资料
  2. 2. 类的继承关系
  3. 3. 线程池的作用
  4. 4. 使用规则
    1. 4.1. runnableTaskQueue
    2. 4.2. RejectedExecutionHandler(饱和策略)
  5. 5. 线程池的使用 execute submit
    1. 5.1. execute 不会返回线程执行是否成功
    2. 5.2. submit 返回一个future对象可以阻塞获取返回值
  6. 6. 线程池的关闭
  7. 7. Callable &Future &FutureTask
    1. 7.1. Callable接口
    2. 7.2. Future接口
    3. 7.3. FutureTask类(同时实现了Runnable、Future)
  8. 8. 数据库连接池原理
  9. 9. 使用案例
  10. 10. 数据库的连接池管理

参考资料

大牛博客:宏观上分析 线程池
http://ifeve.com/java-threadpool/

CSDN系列专栏简易
http://blog.csdn.net/column/details/javathreadpool.html

死磕java并发系列有4篇线程池相关的
http://cmsblogs.com/?p=2122

类的继承关系

http://cmsblogs.com/?p=2444

  1. Executor作为顶层接口,只提供一个execute()接口方法
  2. ThreadPoolExecutor继承AbstractExecutorService抽象类–>ExcutorService接口–>Executor顶层接口
  3. Executors静态工厂类,提供了很多的通用线程池的静态方法

线程池的作用

  1. 节省资源:复用线程,减少重复创建和销毁线程
  2. 提升响应速度:如果有可以复用的线程,不需要创建新线程,直接执行业务操作,提升速度
  3. 方便管理,提供了线程池的shutdown、shutdownnow、isTerminated、isShutDown等方法
  4. 削峰限流,不让一下子过多的线程把程序搞崩,比如RocketMQ里面的Consumer就会把获取到的消息放入到线程池里来慢慢消费
    public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler)

使用规则

优先级: 基本线程池 > BlockingQueue >最大线程池 >饱和策略

  1. 线程池判断基本线程池是否已满?没满,创建一个工作线程来执行任务,即使有空闲的已经创建的线程也不会复用。满了,则进入下个流程。
  2. 线程池判断工作队列是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程
  3. 线程池判断整个线程池是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务

runnableTaskQueue

该阻塞队列里面塞的不是普通的实体类,而是Runnable的实现类,和一般的生产消费模型不一样。线程池完成一个线程后,会尝试从队列里面getTask()。

  • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
  • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
  • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
  • PriorityBlockingQueue:一个具有优先级得无限阻塞队列。

RejectedExecutionHandler(饱和策略)

  • AbortPolicy,默认饱和策略,直接抛出异常
  • CallerRunsPolicy:只用调用者所在线程来运行任务
  • DiscardPolicy:不处理,丢弃掉,也不会日志什么的
  • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
  • 自定义Police,需要实现RejectedExecutionHandler

线程池的使用 execute submit

execute 不会返回线程执行是否成功

threadsPool.execute(new Runnable() {});

submit 返回一个future对象可以阻塞获取返回值

Future future=threadsPool.submit(new Runnable() {});
Boolean result= future.get();

线程池的关闭

shutdown或shutdownNow方法来关闭线程池,但是它们的实现原理不同,

  • shutdown的原理是只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
  • shutdownNow的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。shutdownNow会首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。

Callable &Future &FutureTask

http://blog.csdn.net/javazejian/article/details/50896505

Callable接口

  • 加强版的Runnable,有返回值,会抛出异常

    public interface Runnable {
    public abstract void run();
    }
    public interface Callable<V> {
    V call() throws Exception;
    }
  • 可以作为参数,被线程池调用执行,Future submit(Callable task);

Future接口

作为异步计算的顶层接口,Future对具体的Runnable或者Callable任务提供了三种操作:

  • 执行任务的取消:cancel()
  • 查询任务的状态: isDone()、isCancelled()
  • 获取任务的执行结果(只有Callable任务才有,而且是阻塞):get()、V get(Long timeout , TimeUnit unit)

FutureTask类(同时实现了Runnable、Future)

  • 既可以作为一个Runnable实现类在线程池中执行,甚至可以直接new Thread(futureTask).start();也可以作为一个future获取其他线程的执行结果和状态,
  • done():异步计算完成后调用的回调函数

数据库连接池原理

  • 解决的问题:频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。解决方案:连接复用。
  • 大部分连接池可以设置最大连接数,最小连接数,最大闲置时间等参数,连接池根据这些参数,新建和关闭连接

使用案例

Executors 类里面实现了一些常用的工具方法,返回适合不同业务场景的线程池实现类。
但是要注意FixedThreadPool和SingleThreadPool都是定长的线程池,但是排队队列都是无限长的;CachedThreadPool和ScheduledThreadPool都是可以启动无数个线程来完成功能,都要注意不能OOM了。

  1. FixedThreadPool,固定线程数量的线程池,配合一个无界的LinkedBlockingQueue,重复复用指定数量的coresize的线程

    public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
    0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>());
    }
  2. SingleThreadPool,固定使用一个线程来工作,但是可以无限堆积,因为是单个线程,所以它可以保证认为是按顺序执行的,因为LinkedBlockingQueue是严格的FIFO的

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
  1. CachedThreadPool,同步线程池,默认非公平的

    public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
    60L, TimeUnit.SECONDS,
    new SynchronousQueue<Runnable>());
    }
  2. ScheduledThreadPool,指定核心线程数的定时执行线程池,使用时通过 pool.schedule调用,指定延迟时间,依赖DelayedWorkQueue来实现

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
    new DelayedWorkQueue());
    }
    ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
    for (int i = 0; i < 5; i++) {
    Future<Integer> result = pool.schedule(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
    int num = new Random().nextInt(100);//生成随机数
    System.out.println(Thread.currentThread().getName() + " : " + num);
    return num;
    }
    }, 3, TimeUnit.SECONDS);
    System.out.println(result.get());
    }
    pool.shutdown();

数据库的连接池管理

https://www.cnblogs.com/happySmily/p/5941813.html

常见的数据库连接池:dbcp、c3p0、druid | weblogic(收费的)
常见参数:

  1. initialSize=10: 程序一启动就自动创建 N个数据库长连接
  2. timeBetweenEvictionRunsMillis = “30000” ,程序启动后,每隔30scheck一下当前线程数是否合格:A)Idle线程是否超时,超时就回收掉 B)当前可用线程是否大于minIdle,小于就自动创建,如果设置为非正数,则不运行空闲连接回收器线程,默认是-1,不启动单独线程维护minIdle
  3. maxIdle:当可用线程>minIdle但是小于maxIdle的时候,空闲过期就会被回收
  4. maxActive:当可用线程超过maxIdle的,小于maxActive的时候,使用完就立刻回收
  5. maxWait=3000; 这个指的是最大等待时间,如果超过3秒还未分配到连接,就报错
maxWait="3000" 从池中取连接的最大等待时间,单位ms.
initialSize="10" 初始化连接
minIdle="10" 最小空闲连接
maxIdle="60" 最大空闲连接
maxActive="80" 最大活动连接
validationQuery = "SELECT 1" 验证使用的SQL语句
testWhileIdle = "true" 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
testOnBorrow = "false" 借出连接时不要测试,否则很影响性能
timeBetweenEvictionRunsMillis = "30000" 每30秒运行一次空闲连接回收器
minEvictableIdleTimeMillis = "1800000" 池中的连接空闲30分钟后被回收
numTestsPerEvictionRun="10" 在每次空闲连接回收器线程(如果有)运行时检查的连接数量
removeAbandoned="true" 连接泄漏回收参数,当可用连接数少于3个时才执行
removeAbandonedTimeout="180" 连接泄漏回收参数,180秒,泄露的连接可以被删除的超时值
Contents
  1. 1. 参考资料
  2. 2. 类的继承关系
  3. 3. 线程池的作用
  4. 4. 使用规则
    1. 4.1. runnableTaskQueue
    2. 4.2. RejectedExecutionHandler(饱和策略)
  5. 5. 线程池的使用 execute submit
    1. 5.1. execute 不会返回线程执行是否成功
    2. 5.2. submit 返回一个future对象可以阻塞获取返回值
  6. 6. 线程池的关闭
  7. 7. Callable &Future &FutureTask
    1. 7.1. Callable接口
    2. 7.2. Future接口
    3. 7.3. FutureTask类(同时实现了Runnable、Future)
  8. 8. 数据库连接池原理
  9. 9. 使用案例
  10. 10. 数据库的连接池管理