Android线程池
来源:互联网 发布:如何禁用端口 编辑:程序博客网 时间:2024/06/05 08:40
介绍
多线程技术主要解决处理器单元多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
当同时并发多个网络线程的时候,为了防止内存过度消耗和并发线程过多,控制活动线程的数量,线程池可以限制创建线程的数目,以极大的提高App的性能。
假设在一个APP完成一项任务的时间为
显然,
线程池的优点
- 避免线程的创建和销毁带来的性能开销。
- 能够很好的控制并发线程数,提高资源的利用率,避免大量的线程间因互相抢占系统资源导致的阻塞现象。
- 能够对线程进行简单的管理并提供定时执行、间隔执行、并发数量、并发模式,队列模式等定制功能。
线程池的基本组成
- 线程池管理器(ThreadPool):用于创建和管理线程池,包括创建线程池、销毁线程池、添加新任务。
- 工作线程(PoolWorker):线程池中的线程,在没有任务的时候处于等待的状态,可以循环执行任务。
- 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口、任务执行完之后的收尾工作、任务的执行状态等等。
- 任务队列(TaskQueue):用于存放没有处理的任务,提供一种缓冲机制。
线程池技术正式关注如何缩短或者调整
线程池不仅仅调整了
假如一个服务器每天的要处理10W个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生的线程总数不会超过线程池中线程的数目;如果服务器不利用线程池来处理这些请求,则线程总数为10W个。一般的线程池是远小于10W个的,所以利用线程池的服务器程序是不会为了创建10W个线程而在处理请求的时候浪费时间,从而提高效率。
- CachedThreadPool:缓存型池子,先查看池中有没有以前创建的线程,如果有就重用,如果没有就建一个新的线程加入池子中。能重用的线程必须是timeout IDLE内的池中线程,默认timeout是60s(默认是60s),超过这个IDLE时长,线程实例将被终止并移出池。缓存型池子通常用于执行一些生存期很短的异步型任务。
- FixedThreadPool:创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小,线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。和CachedThreadPool不同的是,FixedThreadPool池线程数是固定的,但是0秒IDLE(无IDLE)。这也就意味着创建的线程会一直存在。所以FixedThreadPool多针对一些很稳定的、很固定的正规并发线程,多用于服务器。
- ScheduledThreadPool:调度型线程池。支持定时以及周期性的任务执行,类似与Timer,0秒IDLE(无IDLE)。
- SingleThreadExecutor:单例线程,任意时间池中只能有一个线程,并且所有的任务是串行执行的,保证所有任务按照制定顺序先进先出(FIFO)执行。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。
代码演示
public class MainActivity extends AppCompatActivity implements View.OnClickListener { /** * 依据CPU的个数创建活动线程的个数 */ private static final int COUNT = Runtime.getRuntime().availableProcessors() * 3 + 2; private static final String TAG = "Executor"; private static ExecutorService mCacheThreadExecutor; private static ExecutorService mFixedThreadExecutor; private static ScheduledExecutorService mScheduleThreadExecutor; private static ExecutorService mSingleThreadExecutor; private Button cached; private Button fixed; private Button scheduled; private Button single; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initListener(); initExecutorService(); } private void initListener() { this.cached.setOnClickListener(this); this.fixed.setOnClickListener(this); this.scheduled.setOnClickListener(this); this.single.setOnClickListener(this); } private void initView() { this.cached = findViewById(R.id.cache); this.fixed = findViewById(R.id.fix); this.scheduled = findViewById(R.id.schedule); this.single = findViewById(R.id.single); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.cache: ExecutorServiceThread(mCacheThreadExecutor); break; case R.id.fix: ExecutorServiceThread(mFixedThreadExecutor); break; case R.id.schedule: ExecutorScheduleThread(mScheduleThreadExecutor); break; case R.id.single: ExecutorServiceThread(mSingleThreadExecutor); break; default: break; } } private void initExecutorService() { // 一个没有限制最大线程数的线程池, // 由60的的生存周期,过了60s就会被移出线程池。 mCacheThreadExecutor = Executors.newCachedThreadPool(); // 限制线程池大小为count的线程池 mFixedThreadExecutor = Executors.newFixedThreadPool(COUNT); // 一个按照制定时间周期性执行的线程池 mScheduleThreadExecutor = Executors.newScheduledThreadPool(COUNT); // 每次只执行一个线程任务的线程池 mSingleThreadExecutor = Executors.newSingleThreadExecutor(); } private void ExecutorServiceThread(ExecutorService executorService) { for (int i = 0;i < 9; i++) { final int index = i; executorService.execute(() -> { try { // 暂停两秒钟 Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "Thread:" + Thread.currentThread().getId() + ",activeCount:" + Thread.activeCount() + ",index:" + index); }); } } private void ExecutorScheduleThread(ScheduledExecutorService executorService) { for (int i = 0;i < 9; i++) { final int index = i; executorService.schedule(() -> { try { // 暂停两秒钟 Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "Thread:" + Thread.currentThread().getId() + ",activeCount:" + Thread.activeCount() + ",index:" + index); }, 2, TimeUnit.SECONDS); } }}
CachedThreadPool
启动CachedThreadPool:
等待60秒:
从图中可以看出,191~199是最先创建的线程。过了60秒,重新点击创建线程的按钮的时候,由于当前的线程池中的线程的生存周期已过且都被移出线程池,因此新建了200~208号线程。
让我们直接在IDEA中直接演示我们写的代码的效果:
注意:途中使用的线程监控的软件是JDK自带的,位于JDK的BIN目录下的jconsole
。
FixedThreadPool
从两次中可以看出,FixedThreadPool创建的线程会一直存在。
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。并且创建的线程会一直的存在在线程池中。
ScheduledThreadPool
依次按照delay的时间执行或者周期性执行。
每隔两秒会执行一次。
SingleThreadExecutor
SingleThreadExecutor中线程池中等待的线程会等待正在的线程执行完之后才会开始执行。
Android网络请求使用示例
public void startThread(Runnable runnable) { ThreadFactory threadFactory = new ThreadFactoryBuilder() .setNameFormat("mdns-pool-%d").build(); ExecutorService singleThreadPool = new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy() ); singleThreadPool.execute(runnable); singleThreadPool.shutdown();}
说明:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);}
allowCoreThreadTimeOut(boolean value)
设置为 true 时,闲置的核心线程会存在超时机制,如果在指定时间没有新任务来时,核心线程也会被终止,而这个时间间隔由第3个属性 keepAliveTime 指定。 maximumPoolSize 线程池所能容纳的最大线程数,当活动的线程数达到这个值后,后续的新任务将会被阻塞。 keepAliveTime 控制线程闲置时的超时时长,超过则终止该线程。一般情况下用于非核心线程,只有在 ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value
) 设置为 true时,也作用于核心线程。 unit 用于指定 keepAliveTime 参数的时间单位,TimeUnit 是个 enum 枚举类型,常用的有:TimeUnit.HOURS(小时)、TimeUnit.MINUTES(分钟)、TimeUnit.SECONDS(秒) 和 TimeUnit.MILLISECONDS(毫秒)等。 workQueue 线程池的任务队列,通过线程池的 execute(Runnable command) 方法会将任务 Runnable 存储在队列中。 threadFactory 线程工厂,它是一个接口,用来为线程池创建新线程的。附录
- Android物联网开发——基于Android Studio环境(何福贵编著)
- 线程、多线程与线程池总结
- 写得很清晰的一篇文章。
- JAVA进阶—-ThreadPoolExecutor机制
- Java(线程)Android线程池
- Android线程,线程池相关
- Android 线程和线程池
- Android线程与线程池
- Android线程和线程池
- Android 线程和线程池
- Android线程和线程池
- Android线程与线程池
- Android线程和线程池
- Android线程与线程池
- Android 线程和线程池
- Android线程和线程池
- Android线程和线程池(四)--Android线程池
- Android ExecutorService线程池
- Android 线程池管理 .
- Android 线程池管理
- Android ExecutorService线程池
- Android 线程池管理
- JAVA 实现 CRC16算法
- 提莫队长蓄势待发.
- Linux修改固定IP和查看网关命令
- NTFS文件系统数据恢复----解析MFT表
- SpringBoot报错(五) Failed to load ApplicationContext (2)
- Android线程池
- [BFS][哈希]Magic Squares 魔板
- linux查看历史命令history
- Jquery实现input keydown回车触发事件(任意触发、指定触发)
- leetcode 402. Remove K Digits 贪心算法 + DFS深度优先遍历
- Android SD卡存储封装类
- 【Spark】worker、executor、stage、task、partition关系
- spark(6)-spark RDD(course14)
- SQLite 约束