Android开发ThreadPoolExecutor与自定义线程池详解

目录
  • 概述
  • ThreadPoolExecutor 类
    • 构造方法
    • 线程池原理
      • 无界和有界队列:
      • 存入:
      • 获取:
    • 创建线程池的构造方法
  • 自定义线程池
    • 1、编写任务类
    • 2、编写线程类,用于执行任务
    • 3、编写线程池类,用于管理线程的执行
    • 4、测试
  • 文末

概述

1、ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务;

2、Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。

3、先来了解其线程池管理的机制,有助于正确使用,避免错误使用导致严重故障。同时可以根据自己的需求实现自己的线程池

ThreadPoolExecutor 类

构造方法

public ThreadPoolExecutor(
	int corePoolSize,					//核心线程数量:如果当前运行的线程数量没有达到 corePoolSize,则新建一个线程,否则加入到任务队列中
	int maximumPoolSize,				//最大线程数:当前系统最多存在的线程数
	long keepAliveTime,					//最大空闲时间:线程空闲的最大时间,超出时间该线程会销毁;设置allowCodeThreadTimeOut(true/false),可控制核心线程是否销毁,默认false 表示允许核心线程即使超过最大线程时间也不会销毁
	TimeUnit unit,						//时间单位:	线程空闲的最大时间的单位
	BlockingQueue<Runnable> workQueue,	//任务队列:	核心线程数量满了之后,提交的任务加入到队列中,等待核心线程数减少后再去创建线程;当任务队列已满,但没有达到最大线程数时,则新建非核心线程
	ThreadFactory threadFactory,		//线程工厂:	自定义线程的创建
	RejectedExecutionHandler handler	//饱和处理机制:当任务队列已满且达到最大线程数时,采取的措施
)

线程池原理

线程池底层使用**堵塞式队列 BlockingQueue **。

队列遵从:先进先出,后进后出原则。 阻塞队列(BlockingQueue)和非阻塞队列(ConcurrentLinkedQueue )区别:

无界和有界队列:

ConcurrentLinkedQueue 是无界队列,不用设置长度,可以随便存放值(其实是jdk伪造的,最大长度是Integer的最大值) BlockingQueue 是有界队列,需要设置长度。 注意:如果BlockingQueue 不设置等待时间就是非阻塞队列

存入:

非阻塞队列:如果存放超出了队列总数,添加不进去,就会丢失。 阻塞队列:如果存放超出了队列总数,进行等待,直到有队列出列,或者超时设置的等待时间)

获取:

非阻塞队列:如果为空时,返回空。 阻塞队列:如果为空时,进行等待,直到有新的队列入列,或者超过设置的等待时间

创建线程池的构造方法

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue)
  • ThreadPoolExecutor
  • 参数说明
  • 核心线程大小(corePoolSize)
  • 最大线程大小(maximumPoolSize)
  • 终止时间(keepAliveTime)
  • Unit 超时时间
  • workQueue 线程容器

自定义线程池

1、编写任务类

public class MyTask implements Runnable{
	//任务id
	private int id;
	public MyTask(int id){
	    this.id=id;
	}
	@Override
	public void run() {
	    String name=Thread.currentThread().getName();
	    System.out.println("线程:"+name+"-->即将执行任务"+id);
	    try {
	        Thread.sleep(200);
	    } catch (InterruptedException e) {
	        e.printStackTrace();
	    }
	    System.out.println("线程:"+name+"执行完成"+id);
	}
	@Override
	public String toString() {
	    return "MyTask{" +
	            "id=" + id +
	            '}';
	}
}

2、编写线程类,用于执行任务

public class MyThread extends  Thread{
    private List<Runnable> tasks;
    public MyThread(String name, List<Runnable> tasks){
        super(name);
        this.tasks=tasks;
    }
    @Override
    public void run() {
        while (tasks.size() > 0){
            Runnable r= tasks.remove(0);
            r.run();
        }
    }
}

3、编写线程池类,用于管理线程的执行

public class MyThreadPool {
    private List<Runnable>  tasks = Collections.synchronizedList(new LinkedList<>());
    /**
     * 当前线程数
     */
    private int num;
    /**
     * 核心线程数
     */
    private int corePoolSize;
    /**
     * 最大线程数
     */
    private int maxSize;
    /**
     * 任务队列数
     */
    private int workSize;
    public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
        this.corePoolSize = corePoolSize;
        this.maxSize = maxSize;
        this.workSize = workSize;
    }
    /**
     * 提交任务
     */
    public void submit(Runnable r){
        if (tasks.size()>=workSize && tasks.size() > maxSize){
            System.out.println("任务:"+r+"被丢弃了");
        }else{
            tasks.add(r);
            execTask(r);
        }
    }
    public void execTask(Runnable r){
        if (corePoolSize > num){
            new MyThread("核心线程:"+num,tasks).start();
            num++;
        }else  if(num < maxSize){
            new MyThread("非核心线程:"+num,tasks).start();
            num++;
        }else{
            System.out.println("任务:"+r+"被缓存了");
        }
    }
}

4、测试

public class Demo {
    public static void main(String[] args) {
        MyThreadPool myThreadPool = new MyThreadPool(2, 4, 20);
        for (int i =0;i< 300;i++){
            MyTask myTask = new MyTask(i);
            myThreadPool.submit(myTask);
        }
    }
}

以上就是Android开发中ThreadPoolExecutor与自定义线程池;

文末

1、用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM

2、如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交。保证不抛弃一个任务

3、最大线程数一般设为2N+1最好,N是CPU核数

4、核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数

5、如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果

以上就是Android开发ThreadPoolExecutor与自定义线程池详解的详细内容,更多关于Android ThreadPoolExecutor的资料请关注我们其它相关文章!

(0)

相关推荐

  • ScheduledThreadPoolExecutor巨坑解决

    目录 概述 坑是啥? 怎么坑的? 总结 概述 最近在做一些优化的时候用到了ScheduledThreadPoolExecutor. 虽然知道这个玩意,但是也很久没用,本着再了解了解的心态,到网上搜索了一下,结果就发现网上有些博客在说ScheduledThreadPoolExecutor有巨坑!!! 瞬间,我的兴趣就被激起来了,马上进去学习了一波- 不看不知道,看完后马上把我的代码坑给填上了- 下面就当记录一下吧,顺便也带大家了解了解,大家看完后也赶紧看看自己公司的项目代码有没有这种漏洞,有的话赶

  • java高并发ScheduledThreadPoolExecutor与Timer区别

    目录 正文 二者的区别 线程角度 系统时间敏感度 是否捕获异常 任务是否具备优先级 是否支持对任务排序 能否获取返回的结果 二者简单的示例 Timer类简单示例 ScheduledThreadPoolExecutor类简单示例 正文 JDK 1.5开始提供ScheduledThreadPoolExecutor类,ScheduledThreadPoolExecutor类继承ThreadPoolExecutor类重用线程池实现了任务的周期性调度功能.在JDK 1.5之前,实现任务的周期性调度主要使用

  • ThreadPoolExecutor参数含义及源码执行流程详解

    目录 背景 典型回答 考点分析 知识拓展 execute() VS submit() 线程池的拒绝策略 自定义拒绝策略 ThreadPoolExecutor 扩展 小结 背景 线程池是为了避免线程频繁的创建和销毁带来的性能消耗,而建立的一种池化技术,它是把已创建的线程放入“池”中,当有任务来临时就可以重用已有的线程,无需等待创建的过程,这样就可以有效提高程序的响应速度.但如果要说线程池的话一定离不开 ThreadPoolExecutor ,在阿里巴巴的<Java 开发手册>中是这样规定线程池的

  • java贪吃蛇极速版

    本文为大家推荐了一款由java实现经典小游戏:贪吃蛇,相信大家都玩过,如何实现的呐? 效果图: 废话不多说,直接奉上代码: 1. public class GreedSnake { public static void main(String[] args) { SnakeModel model = new SnakeModel(20,30); SnakeControl control = new SnakeControl(model); SnakeView view = new SnakeVi

  • Android开发之如何自定义数字键盘详解

    前言 这篇文章是介绍Android中自定义键盘的一些套路,通过定义一个数字键盘为例,本篇的文章语言是基于Kotlin实现的,如果还没有用或者不熟悉该语言的同学,可以自己补习,我之前也写过入门文章. 效果图 github:源码传送门 本地下载:源码传送门 加载键盘存储键属性的XML描述 我们下面的介绍都是依靠上图的实现来展开的,首先是软键盘的布局,我们需要我们的res/xml目录下创建一个xml文件,根节点就是Keyboard,然后就是键盘的每一行Row,每一行中可以指定每一列,也就是具体的键Ke

  • java线程池详解及代码介绍

    目录 一.线程池简介 二.四种常见的线程池详解 三.缓冲队列BlockingQueue和自定义线程池ThreadPoolExecutor 总结 一.线程池简介 线程池的概念 线程池就是首先创建一些线程,它们的集合称为线程池,使用线程池可以很好的提高性能,线程池在系统启动时既创建大量空闲的线程,程序将一个任务传给线程池.线程池就会启动一条线程来执行这个任务,执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务. 线程池的工作机制 在线程池的编程模式下,任务是提交给整个

  • Springboot 配置线程池创建线程及配置 @Async 异步操作线程池详解

    目录 前言 一.创建一个Springboot Web项目 二.新建ThreadPoolConfig 三.新建controller测试 四.演示结果 前言 众所周知,创建显示线程和直接使用未配置的线程池创建线程,都会被阿里的大佬给diss,所以我们要规范的创建线程. 至于 @Async 异步任务的用处是不想等待方法执行完就返回结果,提高软件前台响应速度,一个程序中会用到很多异步方法,所以需要使用线程池管理,防止影响性能. 一.创建一个Springboot Web项目 需要一个Springboot项

  • nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言 nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,nginx为什么不采用多线程模型(这个除了之前一篇文章讲到的情况,别的只有去问作者了,HAHA).其实,nginx代码中提供了一个thread_pool(线程池)的核心模块来处理多任务的.下面就本人对该thread_pool这个模块的理解来跟大家做些分享(文中错误.不足还请大家指出,谢谢) 二.thread_

  • 基于tomcat的连接数与线程池详解

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xml 中写到过:Connector的主要功能,是接收连接请求,创建Request和Response对象用于和请求端交换数据:然后分配线程让Engine(也就是Servlet容器)来处理这个请求,并把产生的Request和Response对象传给Engine.当Engine处理完请求后,也会通过Conn

  • Android开发使用HttpURLConnection进行网络编程详解【附源码下载】

    本文实例讲述了Android开发使用HttpURLConnection进行网络编程.分享给大家供大家参考,具体如下: --HttpURLConnection URLConnection已经可以非常方便地与指定站点交换信息,URLConnection下还有一个子类:HttpURLConnection,HttpURLConnection在URLConnection的基础上进行改进,增加了一些用于操作HTTP资源的便捷方法. setRequestMethod(String):设置发送请求的方法 get

  • Android开发Kotlin实现圆弧计步器示例详解

    目录 效果图 定义控件的样式 自定义StepView 绘制文本坐标 Android获取中线到基线距离 效果图 定义控件的样式 看完效果后,我们先定义控件的样式 <!-- 自定义View的名字 StepView --> <!-- name 属性名称 format 格式 string 文字 color 颜色 dimension 字体大小 integer 数字 reference 资源或者颜色 --> <declare-styleable name="StepView&q

  • Android开发数据结构算法ArrayList源码详解

    目录 简介 ArrayList源码讲解 初始化 扩容 增加元素 一个元素 一堆元素 删除元素 一个元素 一堆元素 修改元素 查询元素 总结 ArrayList优点 ArrayList的缺点 简介 ArrayList是List接口的一个实现类,它是一个集合容器,我们通常会通过指定泛型来存储同一类数据,ArrayList默认容器大小为10,自身可以自动扩容,当容量不足时,扩大为原来的1.5倍,和上篇文章的Vector的最大区别应该就是线程安全了,ArrayList不能保证线程安全,但我们也可以通过其

  • Android 开发中使用Linux Shell实例详解

    Android 开发中使用Linux Shell实例详解 引言 Android系统是基于Linux内核运行的,而做为一名Linux粉,不在Android上面运行一下Linux Shell怎么行呢? 最近发现了一个很好的Android Shell工具代码,在这里分享一下. Shell核心代码 import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.

  • Android开发使用URLConnection进行网络编程详解

    本文实例讲述了Android开发使用URLConnection进行网络编程.分享给大家供大家参考,具体如下: URL的openConnection()方法将返回一个URLConnection,该对象表示应用程序和URL之间的通信连接,程序可以通过URLConnection实例向该URL发送请求,读取URL引用的资源.通常创建一个和URL的连接,并发送请求,读取此URL引用的资源. 需要如下步骤: a)通过调用URL对象openConnection()方法来创建URLConnection对象 b)

随机推荐