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

线程池的种类

在前面的《 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的使用代码例子:
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的使用代码例子:
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开发笔记的完整目录
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值