Android 线程池的封装

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 线程池的封装相关的知识,希望对你有一定的参考价值。

参考技术A GlobalThreadPools.java:

调用:

线程池
线程池概念来源于Java中的Executor,它是一个接口,真正的实现为ThreadPoolExecutor。ThreadPoolExecutor提供了一系列参数来配置线程池。
优点
1:重用线程池中的线程,线程在执行完任务后不会立刻销毁,而会等待另外的任务,这样就不会频繁地创建、销毁线程和调用GC。。
2:有效控制线程池的最大并发数,避免大量线程抢占资源出现的问题。
3:对多个线程进行统一地管理,可提供定时执行及指定间隔循环执行的功能。
ThreadPoolExecutor 有多个重载方法,但最终都调用了这个构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数:
corePoolSize:线程池中核心线程的数量;为了内存优化,在线程池维护了几个重要的线程,不达到一定条件不开辟其余线程
maximumPoolSize :线程池中最大线程数量:这个数量是包括核心线程的,当线程池中的正在执行的线程池达到了这个数字,再提交线程如果你不做特殊处理将会抛出异常
keepAliveTime:非核心线程的超时时长;当线程池中的非核心线程闲置时间超过这个值代表的时间后,将会被回收;同时如果调用ThreadPoolExecutor.allowCoreThreadTimeOut(true),那么核心线程也会符合这个设置
unit:keepAliveTime值的单位,可以是时分秒等
workQueue:存放待执行的线程;你通过execute方法提交线程,但是这些线程还没达到执行条件,那么就会保存在这个队列里
threadFactory:创建线程池的工厂;在这个工厂里,我们可以指定线程的一些信息
handler:线程提交拒绝策略;通常是线程池中的正在执行的线程数量已经达到了最大线程数或线程池关闭,如果不传,默认是抛出一个RejectedExecutionException,所以最好传下

推荐使用 Executors 的工厂方法来创建线程池,通过直接或间接的配置 ThreadPoolExecutor 的参数来构建线程池,常用的线程池有如下 4 种,newFixedThreadPool ,newCachedThreadPool,
newScheduledThreadPool 和 newSingleThreadExecutor。

ThreadPoolExecutor 执行任务时大致遵循如下流程:
1.如果线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行。
2.如果线程池中的线程数已经达到核心线程数,且任务队列workQueue未满,则将新线程放入workQueue中等待执行。
3.如果线程池中的线程数已经达到核心线程数但未超过线程池规定最大值,且workQueue已满,则开启一个非核心线程来执行任务。
4.如果线程池中的线程数已经超过线程池规定最大值,则拒绝执行该任务,采取饱和策略,并抛出RejectedExecutionException异常。

线程池大小:(N为CPU数量)
如果是CPU密集型应用,则线程池大小设置为N+1
如果是IO密集型应用,则线程池大小设置为2N+1
I/O密集型
指的是系统的CPU效能相对硬盘/内存的效能要好,大部分的状况是 CPU 在等 I/O (硬盘/内存) 的读/写, CPU Loading 不高。
CPU密集型
指的是系统的 硬盘/内存 效能 相对 CPU 的效能 要好,大部分的状况是 CPU Loading 100%,CPU 要读/写 I/O (硬盘/内存),I/O在很短的时间就可以完成,而 CPU 还有许多运算要处理,CPU Loading 很高。
获取CPU数量的方法为:
Runtime.getRuntime().availableProcessors();

摘自:
https://blog.csdn.net/qq_30993595/article/details/84324681

Spring中线程池的用法

多线程并发处理起来通常比较麻烦,如果你使用spring容器来管理业务bean,事情就好办了多了。spring封装了java的多线程的实现,简化了开发。

简单的Hello程序

需要执行的线程类

一般是对于业务的封装.将具体的业务逻辑放到,线程内执行。

public class MessagePrinterTask implements Runnable 
    private String message;

    public MessagePrinterTask() 

    

    public MessagePrinterTask(String message) 
        this.message = message;
    

    public void run() 
        try 
            Thread.sleep(3000);
            System.out.println(message);
         catch (InterruptedException e) 
            e.printStackTrace();
        

    

    @Override
    public String toString() 
        return "MessagePrinterTask [message=" + message + "]";
    

spring 的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="  
http://www.springframework.org/schema/beans        
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
http://www.springframework.org/schema/context                
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- 异步线程池 -->
    <bean id="taskExecutor"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 核心线程数 -->
        <property name="corePoolSize" value="10" />
        <!-- 最大线程数 -->
        <property name="maxPoolSize" value="50" />
        <!-- 队列最大长度 >=mainExecutor.maxSize -->
        <property name="queueCapacity" value="100" />
        <!-- 线程池维护线程所允许的空闲时间 -->
        <property name="keepAliveSeconds" value="300" />
        <!-- 线程池对拒绝任务(无线程可用)的处理 策略 -->
        <!-- 若不作该处理,当线程满了,队列满了之后,继续往下增加任务,则抛出异常,拒绝该任务 -->
        <!-- <property name="rejectedExecutionHandler"> <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /> </property> -->
    </bean>

    <!-- 处理业务的线程 -->
    <bean id="messagePrinterTask" class="com.test.sping.thread.MessagePrinterTask" />

</beans>

测试代码

  • 测试代码
import java.util.concurrent.Executor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ThreadTest 
    public static void main(String[] args) 

        ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Executor executor = (Executor) appContext.getBean("taskExecutor");

        for (int i = 0; i < 10; i++) 
            MessagePrinterTask mTask = new MessagePrinterTask("Message data  is " + i);
            executor.execute(mTask);
        

        System.out.println("I am from Main Thread ...");
    
  • 测试代码的运行结果
I am from Main Thread ...
Message data  is 5
Message data  is 7
Message data  is 6
Message data  is 8
Message data  is 4
Message data  is 9
Message data  is 0
Message data  is 3
Message data  is 1
Message data  is 2

在Spring容器启动的时候,启动一个线程

spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="  
http://www.springframework.org/schema/beans        
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
http://www.springframework.org/schema/context                
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- 执行业务方法的线程 -->
    <bean id="scheduledThread" class="com.test.sping.thread.ScheduledThread" />

    <!-- 这样设置容器一启动就自动运行某个线程 start -->
    <bean id="springScheduleExecutorTask" class="org.springframework.scheduling.concurrent.ScheduledExecutorTask">
        <!-- messagePrinterTask为线程类 -->
        <property name="runnable" ref="scheduledThread" />
        <!-- 容器加载5秒后开始执行 -->
        <property name="delay" value="5000" />
        <!-- 每次任务间隔 2秒,循环执行该线程,删除该设定就容器启动后只执行一次 -->
        <property name="period" value="2000" />
    </bean>

   <!-- 这样设置容器一启动就自动运行某个线程  -->
    <bean id="springScheduledExecutorFactoryBean" class="org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean">
        <property name="scheduledExecutorTasks">
            <list>
                <ref bean="springScheduleExecutorTask" />
            </list>
        </property>
    </bean>


</beans>

业务线程

public class ScheduledThread implements Runnable 

    @Override
    public void run() 

        while (true) 
            try 
                Thread.sleep(5000);
                System.out.println(" I am from ScheduledThread ...");
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    

测试代码

import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ScheduledThreadTest 
    public static void main(String[] args) 

        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext-scheduled.xml");

        try 
            Thread.sleep(Integer.MAX_VALUE);
         catch (InterruptedException e) 
            e.printStackTrace();
        
    

以上是关于Android 线程池的封装的主要内容,如果未能解决你的问题,请参考以下文章

Android线程池的使用

android怎么判断线程池的任务等待

Android中的线程池

线程池的学习和使用

《Android 开发艺术探索》 第11章 --- android 线程和线程池

线程池的基本思想还是一种对象池的思想