前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java多线程学习(3)-线程池

java多线程学习(3)-线程池

原创
作者头像
Simon、hao
发布2018-07-25 17:07:58
3140
发布2018-07-25 17:07:58
举报
文章被收录于专栏:java小记

简介

随着并发的增多,创建、销毁线程的动作也随之增多,所以资源的浪费也随之增多,并且线程的数量变大,管理的难度也会随之加大------于是线程池小伙伴就出来前言

线程池的几个好处
  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

看到这些好处有点心动,但是我们不仅要知其然还要知其所以然

如何使用线程池?

创建线程池

代码语言:txt
复制
ThreadPoolExecutor executor = new ThreadPoolExecutor(
                                                corePoolSize, 
                                                maximumPoolSize,
                                                keepAliveTime, 
                                                milliseconds,
                                                runnableTaskQueue,
                                                threadFactory,
                                                handler);

参数的含义

  • corePoolSize:基本线程池,也叫核心线程池,一般活动的线程数量不会超过此参数的大小;
  • maximumPoolSize:当前线程池允许创建的最大线程数;
  • keepAliveTime:线程活动保持时间,当线程空闲下来时,控制线程存活的时间,当任务执行时间短,任务多,可以提高当前参数的大小,保证线程的利用率
  • milliseconds:时间单位,可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
  • runnableTaskQueue:任务队列,用于保存等待执行的任务的阻塞队列,
  • threadFactory:用于创建线程的工厂,可以设置线程的名称
  • handler:饱和策略,当线程池和队列都饱和的 状态下,必须采取一种策略来处理新提交的任务;

如何提交任务?

executor()

我们可以使用executor向线程池提交任务,但是此种方式没有返回值,无法判断任务是否已经执行成功,参数为runable对象实例;

submit()

此方法不为ThreadPoolExecutor类自有的方法,他是属于ThreadPoolExecutor父类方法,返回future通过get判断任务是否执行成功,get会阻塞直到任务完成,源码如下

submit()
代码语言:txt
复制
public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

不难发现提交任务是传入了ftask对象,看看newTaskFor()

代码语言:txt
复制
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

返回的一个FutureTask实例

查看对应的get方法,返回一个int类型的值

如何关闭线程池

shutdown和shutdownNow

shutdown是将线程池的状态设置为shutdown状态,但是并不会停止正在工作的线程,shutdownNow将线程池的状态设置为stop状态,并且尝试停止正在执行任务的线程

线程池执行的原理

线程池流程分析

当线程池当中有新提交的任务时,判断流程如下:

  1. 基本线程池是否满了?没满,创建工作线程执行任务,满了,继续下面的判断
  2. 判断工作队列是否满了?没满,放入工作队列等待执行,满了,向下执行
  3. 判断线程池是否达到最大线程数?没有,创建新的工作线程,执行任务,满了,按照饱和策略处理
源码
代码语言:txt
复制
public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        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();
            //如果添加时的瞬间有人调用了shutdown方法的应急措施
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

通俗理解

一家工厂,有一个厂房,厂房里有5个工人(基本线程),每个工人负责处理一个机器(任务),这个厂房最多能容纳10个人(最大线程数),这个工厂还有一个仓库,仓库可以存储5个机器,当工人处理一个机器之后,会从仓库拿一个机器继续干活,当需求比较大的时候,老板发现仓库安置不下了,于是将机器直接放到厂房了,同时新招了几个人(总共不超过10个人),在厂房干活,当最后同时有超过15台机器的时候,没地方,也没人了,老板直接不接这个新的单子了(某种饱和策略)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
    • 线程池的几个好处
    • 如何使用线程池?
      • 创建线程池
        • 参数的含义
          • 如何提交任务?
            • executor()
            • submit()
          • 如何关闭线程池
            • shutdown和shutdownNow
        • 线程池执行的原理
          • 线程池流程分析
            • 通俗理解
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档