线程池

2018-07-09 13:28:17来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

继承Thread的弊端

1.每次new Thread的时候都需要新建一个线程,性能差

2.线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM

3.Thread类缺少更多功能,比如更多的执行、定期执行、线程中断。

线程池的好处

1.重用存在的线程,减少对象创建、消亡的开销、性能佳

2.可以有效的控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞。

3.提供定时执行、定期执行、单线程、并发数控制等功能。

 

线程池-ThreadPoolExecutor

参数说明:ThreadPoolExecutor一共有七个参数,这七个参数配合起来,构成了线程池强大的功能。

corePoolSize:核心线程数线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。

maximumPoolSize:线程最大线程数,线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。

workQueue : 阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程产生重大影响

ThreadPoolExecutorexecute方法分下面4种情况。
1)如果当前运行的线程少于corePoolSize则创建新线程来行任(注意,一步骤需要取全局)。
2)如果运行的线程等于或多于corePoolSize将任加入BlockingQueue
3)如果无法将任加入BlockingQueue列已),则创建新的线程来理任(注意,执行一步需要取全局)。
4)如果建新线程将使当前运行的线程超出maximumPoolSize,任将被拒,并用RejectedExecutionHandler.rejectedExecution()方法。

线程池大小调节策略。通过corePoolSize和maximumPoolSize,控制如何新增线程;通过allowCoreThreadTimeOut和keepAliveTime,控制如何销毁线程。

allowCoreThreadTimeOut:

该属性用来控制是否允许核心线程超时退出。如果线程池的大小已经达到了corePoolSize,不管有没有任务需要执行,线程池都会保证这些核心线程处于存活状态。可以知道:该属性只是用来控制核心线程的。

keepAliveTime:

如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut。

unit : keepAliveTime的时间单位

threadFactory:线程工厂,用来创建线程

rejectHandler:当拒绝处理任务时的策略

  • running:能接受新提交的任务,也能处理阻塞队列中的任务
  • shutdown:不能处理新的任务,但是能继续处理阻塞队列中任务
  • stop:不能接收新的任务,也不处理队列中的任务
  • tidying:如果所有的任务都已经终止了,这时有效线程数为0
  • terminated:最终状态
序号方法名描述
1 execute() 提交任务,交给线程池执行
2 submit() 提交任务,能够返回执行结果 execute+Future
3 shutdown() 关闭线程池,等待任务都执行完
4 shutdownNow() 关闭线程池,不等待任务执行完
5 getTaskCount() 线程池已执行和未执行的任务总数
6 getCompleteTaskCount() 已完成的任务数量
7 getPoolSize() 线程池当前的线程数量
8 getActiveCount()

当前线程池中正在执行任务的线程数量

使用Executor创建线程池

使用Executor可以创建四种线程池:分别对应上边提到的四种线程池初始化方法

1、Executors.newCachedThreadPool 
创建一个可缓存的线程池,如果线程池的长度超过了处理的需要,可以灵活回收空闲线程。如果没有可回收的就新建线程。

//使用方法:
public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("task:{}", index);
            }
        });
    }
    executorService.shutdown();
}

 

值得注意的一点是,newCachedThreadPool的返回值是ExecutorService类型,该类型只包含基础的线程池方法,但却不包含线程监控相关方法,因此在使用返回值为ExecutorService的线程池类型创建新线程时要考虑到具体情况。 

2、newFixedThreadPool 
定长线程池,可以线程现成的最大并发数,超出在队列等待

//使用方法:
public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
        final int index = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("task:{}", index);
            }
        });
    }
    executorService.shutdown();
}

3、newSingleThreadExecutor 
单线程化的线程池,用唯一的一个共用线程执行任务,保证所有任务按指定顺序执行(FIFO、优先级…)

//使用方法:
public static void main(String[] args) {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("task:{}", index);
            }
        });
    }
    executorService.shutdown();
}

4、newScheduledThreadPool 
定长线程池,支持定时和周期任务执行

//基础使用方法:
public static void main(String[] args) {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    executorService.schedule(new Runnable() {
        @Override
        public void run() {
            log.warn("schedule run");
        }
    }, 3, TimeUnit.SECONDS);//延迟3秒执行
    executorService.shutdown();
}

小扩展:延迟执行任务的操作,java中还有Timer类同样可以实现

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        log.warn("timer run");
    }
}, new Date(), 5 * 1000);

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:多线程并发与线程安全总结

下一篇:Java : 多态表现:静态绑定与动态绑定(向上转型的运行机制)