前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(七十六)线程池管理

Android开发笔记(七十六)线程池管理

作者头像
aqi00
发布2019-01-18 13:01:22
1.3K0
发布2019-01-18 13:01:22
举报
文章被收录于专栏:老欧说安卓

线程池的种类

在前面的《Android开发笔记(四十八)Thread类实现多线程》,我们介绍了线程类Thread的使用,可是缺乏线程的统一管理,这会产生如下问题: 1、无法控制线程的并发数,一旦同时启动多个线程,可能导致程序挂死; 2、线程之间无法复用,每个线程都经历创建、启动、停止的生命周期,资源开销不小; 3、线程不能被外部有效地杀死,虽然Thread类提供了stop方法,但该方法已经过时,并不推荐使用; 基于以上问题,Java提供了线程池机制,用于对程序内部的线程作统一管理,统一分配、统一调度。Java把线程池分为两大类:普通线程池、定时器线程池,最新的java1.8新加了一类分支/聚合线程池(即ForkJoinPool),但Android尚无ForkJoinPool的定义,所以本文的讨论仅限于前两类。 再具体一点,Android中用到的线程池一共五种,它们都在Executors类中创建,分别是: 1、newCachedThreadPool : 创建一个无个数限制的线程池。 2、newFixedThreadPool : 创建线程数量固定的线程池。 3、newSingleThreadExecutor : 创建只有单个线程的线程池。 4、newScheduledThreadPool : 创建线程数量固定的定时器线程池。 5、newSingleThreadScheduledExecutor : 创建只有单个线程的定时器线程池。 上述五个方法返回的线程池对象都是ExecutorService,它是线程池服务的接口。ExecutorService接口有两个派生类,分别是普通线程池ThreadPoolExecutor,以及定时器线程池ScheduledExecutorService。

ThreadPoolExecutor

要生成普通线程池对象,有两种办法: 1、调用Executors类的方法newCachedThreadPool、newFixedThreadPool,这两个方法返回的类型都是ThreadPoolExecutor。 注意不能用newSingleThreadExecutor,该方法返回的类型是FinalizableDelegatedExecutorService,而不是ThreadPoolExecutor。 2、使用ThreadPoolExecutor自身的构造函数来构建线程池对象,其中构造函数的参数说明如下: int corePoolSize : 最小线程个数 int maximumPoolSize : 最大线程个数 long keepAliveTime : 线程活动时长 TimeUnit unit : 时间单位。一般取值为TimeUnit.SECONDS表示秒;TimeUnit.MILLISECONDS表示毫秒;TimeUnit.MICROSECONDS表示微妙。 BlockingQueue<Runnable> workQueue : 设置等待队列。取值new LinkedBlockingQueue<Runnable>()即可,默认表示等待队列无穷大,此时工作线程等于最小线程个数;当然也可在参数中指定等待队列的大小,此时工作线程数等于总任务数减去等待队列大小,且工作线程数位于最小线程个数与最大线程个数之间。 若计算得到的工作线程数小于最小线程个数,则工作线程数等于最小线程个数;若工作线程数大于最大线程个数,则系统会扔出异常java.util.concurrent.RejectedExecutionException,并不会自动让工作线程数等于最大线程个数。所以等待队列大小要么取默认值(即不设置),要么设的尽可能大,不然一旦程序启动大量线程,便会异常报错。 ThreadFactory threadFactory : 一般默认即可。 下面是ThreadPoolExecutor的常用方法说明: execute : 向执行队列添加指定的Runnable任务。 remove : 从执行队列移除指定的Runnable任务。 shutdown : 关闭线程池。 isTerminated : 判断线程池是否关闭。 setCorePoolSize : 设置最小线程个数。 setMaximumPoolSize : 设置最大线程个数。 setKeepAliveTime : 设置线程活动时长。 getPoolSize : 获取当前的线程个数。 getActiveCount : 获取当前的活动线程个数。

ScheduledExecutorService

前面的博文《Android开发笔记(五十)定时器AlarmManager》,提到了两类定时器,分别是Java自带的Timer/TimerTask,以及Android新增的AlarmManager,这里的ScheduledExecutorService则是第三种定时器。 要生成定时器线程池,也有两种办法: 1、调用Executors类的方法newScheduledThreadPool、newSingleThreadScheduledExecutor,这两个方法返回的类型都是ScheduledExecutorService; 2、使用ScheduledThreadPoolExecutor的构造函数来构建线程池对象(该类继承自ThreadPoolExecutor,但实现了ScheduledExecutorService接口),其中构造函数的参数说明如下: int corePoolSize : 最小线程个数 ThreadFactory threadFactory : 一般默认即可。 RejectedExecutionHandler handler : 一般默认即可。 ScheduledExecutorService继承了ThreadPoolExecutor的所有方法,下面是它多出的几个定时器方法:                        schedule : 延迟一段时间后启动任务。 scheduleAtFixedRate : 先延迟一段时间,然后间隔若干时间周期启动任务。 scheduleWithFixedDelay : 先延迟一段时间,然后固定延迟若干时间启动任务。 注意,scheduleAtFixedRate和scheduleWithFixedDelay都是循环执行任务,它们的区别在于,前者的间隔时间从上个任务开始起计算,后者的间隔时间从上个任务结束起计算。

ThreadFactory

ThreadFactory是在线程池中使用的线程工厂接口,它定义了一个newThread方法,该方法输入Runnable参数,返回Thread对象。一般情况下使用默认的DefaultThreadFactory即可,但在某些特定场合也可以自己实现工厂类,可用来跟踪线程的启动时间、结束时间,以及线程发生异常时的处理步骤。

代码示例

下面是ThreadPoolExecutor的使用代码例子:

代码语言:javascript
复制
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.example.exmthreadpool.util.Utils;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class ThreadPoolActivity extends Activity implements OnClickListener {
	
	private final static String TAG = "ThreadPoolActivity";
	private TextView tv_desc;
	private String mDesc = "";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_thread_pool);

		tv_desc = (TextView) findViewById(R.id.tv_desc);
		Button btn_unlimit_pool = (Button) findViewById(R.id.btn_unlimit_pool);
		Button btn_multi_pool = (Button) findViewById(R.id.btn_multi_pool);
		Button btn_single_pool = (Button) findViewById(R.id.btn_single_pool);
		Button btn_custom_pool = (Button) findViewById(R.id.btn_custom_pool);
		btn_unlimit_pool.setOnClickListener(this);
		btn_multi_pool.setOnClickListener(this);
		btn_single_pool.setOnClickListener(this);
		btn_custom_pool.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_unlimit_pool) {
			ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
			startPool(pool);
		} else if (v.getId() == R.id.btn_multi_pool) {
			ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
			startPool(pool);
		} else if (v.getId() == R.id.btn_single_pool) {
			ExecutorService pool = Executors.newSingleThreadExecutor();
			startPool(pool);
		} else if (v.getId() == R.id.btn_custom_pool) {
			ThreadPoolExecutor pool = new ThreadPoolExecutor(
					2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(19));
			startPool(pool);
		}
	}
	
	private void startPool(ExecutorService pool) {
		mDesc = "";
		for (int i=0; i<20; i++) {
			MyRunnable refresh = new MyRunnable(i);
			pool.execute(refresh);
		}
	}

	private Handler mMyHandler = new MyHandler(this);
	private static class MyHandler extends Handler {
		public static WeakReference<ThreadPoolActivity> mActivity;

		public MyHandler(ThreadPoolActivity activity) {
			mActivity = new WeakReference<ThreadPoolActivity>(activity);
		}

		@Override
		public void handleMessage(Message msg) {
			ThreadPoolActivity act = mActivity.get();
			if (act != null) {
				act.mDesc = String.format("%s\n%s 当前序号是%d", 
						act.mDesc, Utils.getNowDateTime(), msg.arg1);
				act.tv_desc.setText(act.mDesc);
			}
		}
	}

	private static class MyRunnable implements Runnable {
		private int mIndex;
		public MyRunnable(int index) {
			mIndex = index;
		}
		
		@Override
		public void run() {
			try {
				Thread.sleep(2000);
				ThreadPoolActivity act = MyHandler.mActivity.get();
				if (act != null) {
					Message msg = act.mMyHandler.obtainMessage();
					msg.arg1 = mIndex;
					act.mMyHandler.sendMessage(msg);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	};

}

下面是ScheduledExecutorService的使用代码例子:

代码语言:javascript
复制
import java.lang.ref.WeakReference;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.example.exmthreadpool.util.Utils;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class SchedulePoolActivity extends Activity implements OnClickListener {
	
	private final static String TAG = "SchedulePoolActivity";
	private TextView tv_desc;
	private String mDesc = "";
	private int ONCE = 1;
	private int RATE = 2;
	private int DELAY = 3;
	private ScheduledExecutorService mMultiPool;
	private ScheduledExecutorService mSinglePool;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_schedule_pool);

		tv_desc = (TextView) findViewById(R.id.tv_desc);
		Button btn_multi_schedule_once = (Button) findViewById(R.id.btn_multi_schedule_once);
		Button btn_multi_schedule_rate = (Button) findViewById(R.id.btn_multi_schedule_rate);
		Button btn_multi_schedule_delay = (Button) findViewById(R.id.btn_multi_schedule_delay);
		Button btn_single_schedule_once = (Button) findViewById(R.id.btn_single_schedule_once);
		Button btn_single_schedule_rate = (Button) findViewById(R.id.btn_single_schedule_rate);
		Button btn_single_schedule_delay = (Button) findViewById(R.id.btn_single_schedule_delay);
		btn_multi_schedule_once.setOnClickListener(this);
		btn_multi_schedule_rate.setOnClickListener(this);
		btn_multi_schedule_delay.setOnClickListener(this);
		btn_single_schedule_once.setOnClickListener(this);
		btn_single_schedule_rate.setOnClickListener(this);
		btn_single_schedule_delay.setOnClickListener(this);
	}
	
	@Override
	protected void onStart() {
		mMultiPool = (ScheduledExecutorService) Executors.newScheduledThreadPool(3);
		mSinglePool = (ScheduledExecutorService) Executors.newSingleThreadScheduledExecutor();
		super.onStart();
	}
	
	@Override
	protected void onStop() {
		if (mMultiPool.isTerminated() != true) {
			mMultiPool.shutdown();
		}
		if (mSinglePool.isTerminated() != true) {
			mSinglePool.shutdown();
		}
		super.onStop();
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_multi_schedule_once) {
			startPool(mMultiPool, ONCE);
		} else if (v.getId() == R.id.btn_multi_schedule_rate) {
			startPool(mMultiPool, RATE);
		} else if (v.getId() == R.id.btn_multi_schedule_delay) {
			startPool(mMultiPool, DELAY);
		} else if (v.getId() == R.id.btn_single_schedule_once) {
			startPool(mSinglePool, ONCE);
		} else if (v.getId() == R.id.btn_single_schedule_rate) {
			startPool(mSinglePool, RATE);
		} else if (v.getId() == R.id.btn_single_schedule_delay) {
			startPool(mSinglePool, DELAY);
		}
	}

	private void startPool(ScheduledExecutorService pool, int type) {
		mDesc = "";
		for (int i=0; i<1; i++) {
			MyRunnable refresh = new MyRunnable(i);
			if (type == ONCE) {
				pool.schedule(refresh, 1, TimeUnit.SECONDS);
			} else if (type == RATE) {
				pool.scheduleAtFixedRate(refresh, 0, 3, TimeUnit.SECONDS);
			} else if (type == DELAY) {
				pool.scheduleWithFixedDelay(refresh, 0, 3, TimeUnit.SECONDS);
			}
		}
	}

	private Handler mMyHandler = new MyHandler(this);
	private static class MyHandler extends Handler {
		public static WeakReference<SchedulePoolActivity> mActivity;

		public MyHandler(SchedulePoolActivity activity) {
			mActivity = new WeakReference<SchedulePoolActivity>(activity);
		}

		@Override
		public void handleMessage(Message msg) {
			SchedulePoolActivity act = mActivity.get();
			if (act != null) {
				act.mDesc = String.format("%s\n%s 当前序号是%d", 
						act.mDesc, Utils.getNowDateTime(), msg.arg1);
				act.tv_desc.setText(act.mDesc);
			}
		}
	}

	private static class MyRunnable implements Runnable {
		private int mIndex;
		public MyRunnable(int index) {
			mIndex = index;
		}
		
		@Override
		public void run() {
			try {
				Thread.sleep(2000);
				SchedulePoolActivity act = MyHandler.mActivity.get();
				if (act != null) {
					Message msg = act.mMyHandler.obtainMessage();
					msg.arg1 = mIndex;
					act.mMyHandler.sendMessage(msg);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	};

}

点击下载本文用到的线程池管理的工程代码 点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年03月07日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程池的种类
  • ThreadPoolExecutor
  • ScheduledExecutorService
  • ThreadFactory
  • 代码示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档