Android线程池的使用体会

相信大家都听说过线程池这个概念,那么使用线程池的好处可以有效的控制线程并发数量,提高性能,避免由于频繁创建线程到时GC等。其中asynctask可以说就是对线程池的一个封装框架。

线程池常用的四种类型:FixedThreadPool,CachedThreadPool,ScheduledThreadPool,SingleThreadPool.

1.FixedThreadPool:
通过Executors的newFixedThreadPool方法创建。它是一种线程数量固定的线程池,它的核心线程数等于最大线程数,即只有核心线程,而且当线程处于空闲状态时,它们也不会被回收。这意味着它们能够更快的相应外界的请求。另外任务队列也是没有大小限制的。

2.CachedThreadPool:
通过Executors的newCachedThreadPool创建。它是一种线程数量不定的线程池,它只有非核心线程,并且最大线程数为Integer.MAX_VALUE。由于Integer.MAX_VALUE是一个很大的数,实际上就相当于最大线程数可以是任意大。线程池中的空闲线程都有超时机制,这个超时时长为60秒,超过60秒闲置线程就会被回收。它的任务队列相当于一个空集合,这将导致任何任务都会被立即执行。当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会利用空闲的线程来处理新任务。
这类线程池比较适合执行大量的耗时较少的任务。当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这个时候CachedThreadPool之中实际上是没有任何线程的,它几乎是不占用任何系统资源的。


3.ScheduledThreadPool:
通过Executors的newScheduledThreadPool方法创建。它的核心线程数量是固定的,而非核心线程数量是没有限制的(即Integer.MAX_VALUE);这类线程池主要用于执行定时任务和具有固定周期的重复任务。

4.SingleThreadPool:
通过Executors的newSingleThreadPool方法创建。这类线程池内部只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。SingleThreadPool的意义在于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。没有超时机制。

特别是一些Android新手在写网络请求一般都是new thread(new runnable()).start()这种写法。那么这样写。当然有它的缺点。最大缺点就是会导致频繁的创建线程,线程执行完后就被回收,会导致GC。假如同事有10个threa。那么这些线程没有先后顺序,如遇网络状况不好或其他原因或导致卡顿,性能下降等。这对着个问题就衍生除了线程池。

其实Android中的线程池都是通过threadpoolexecutor来配置的。上面也列出了4中线程池类型。

最基础的示例如下:

/**
 * 线程池示例
 * @author W61
 *
 */
@ContentView(value=R.layout.activity_theadpool)
public class ThreadPoolActivity extends BaseActivity{


	public static final String TAG = "ThreadPoolActivity";
	@ViewInject(R.id.threadpool_btn)
	private Button start_threadpool_btn;

	private ThreadPoolExecutor poolExecutor;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		/**
		 * corePoolSize  线程池中核心线程的数量
		 * maximumPoolSize  线程池中最大线程数量
		 * keepAliveTime 非核心线程的超时时长,当系统中非核心线程闲置时间超过keepAliveTime之后,则会被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,则该参数也表示核心线程的超时时长
		 * unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
		 * workQueue 线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
		 * 
		 * MICROSECONDS    微秒   一百万分之一秒(就是毫秒/1000)
		 * MILLISECONDS    毫秒   千分之一秒    
		 * NANOSECONDS   毫微秒  十亿分之一秒(就是微秒/1000)
		 * SECONDS          秒
		 * MINUTES     分钟
		 * HOURS      小时
		 * DAYS      天
		 */
		poolExecutor = new ThreadPoolExecutor(3, 5,  2, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(128));

	}
	@OnClick({ R.id.threadpool_btn})
	public void clickBtn(View view){
		switch (view.getId()) {
		case R.id.threadpool_btn:
			Toast.makeText(this, TAG, Toast.LENGTH_SHORT).show();
			for (int i = 0; i < 12; i++) {  
				final int finalI = i;  
				Runnable runnable = new Runnable() {  
					@Override  
					public void run() {  
						SystemClock.sleep(3000);  
						Log.d(TAG, "run: " + finalI);  
					}  
				};  
				poolExecutor.execute(runnable);  
			}  
			break;

		default:
			break;
		}
	}

}

由上面代码可以看出:线程池的核心线程数量是3.最大线程数量是5,超时是2s,队列任务大小是128.

通俗点说就是。线程启动时,首先会将放入5个线程任务到队列中,让其等待前面线程执行完了,在来执行。每次执行的线程数量是3个。当超时或者线程池涨的数量达到最大等原因就会抛出一个RejectedExecutionException异常。

执行效果图:


代码中休眠了3s是为了更好的看出运行效果。

在把代码稍做修改,如下:

poolExecutor = new ThreadPoolExecutor(3, 10,  2, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(5));
最大线程数量改为10,队列任务改为5.再次运行,效果如下:


会发现打印是0,1,2 ,8,9,10,11,3,4,5,6,7。由此可以看出来,先执行012,在把8 9 10 11放到任务队列中等待。

其他线程池类型,大家可以自己动手测试,也可以结合asynctask的源码来进一步学习了解线程池。

注明:上面博文内容部分参考其他博主的博文。大笑大笑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值