Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待(这种项目中常用)。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
例子:
ExecutorService exec = Executors.newFixedThreadPool(4);
List<FutureTask<String>> list = new ArrayList<FutureTask<String>>(); //任务队列FutureTask的泛型根据需求自定义
FutureTask<String> ft = new FutureTask<String>(new GetPicUrl(image));//多线程上传图片
list.add(ft);
exec.submit(ft);
String pic = list.get(i).get(); //在list任务队列中获取上传是否成功的返回值结果(如果成功会返回一个网络的url图片路径,针对该项目的图片上传功能)
exec.shutdown(); //最后调用shutdown方法不在添加任务队列,之前没执行玩的任务还会执行,如果调用shutdownnow 就都会立即停止所有任务
/** 上传图片任务,实现Callable接口*/
@SuppressWarnings("rawtypes")
class GetPicUrl implements Callable {
private String path;
private String name;
public GetPicUrl(String path) {
this.path = path;
}
@Override
public String call() {
try {
String url = HttpApi.uploadFile(path);// http请求上传本地图片
if (url.startsWith("http:")) {
return url + "," + name;
}
} catch (Exception e) {
return name;
}
return name;
}
}
附: 线程池工程原理
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了
以下是项目中的实际代码:
1、启动上传图片的异步任务
new UpLoadPic().execute();
/** * 上传照片异步任务 */ class UpLoadPic extends AsyncTask<Void, Void, Boolean> { @Override protected void onPreExecute() { processDailog = Utils.showProcessDialog(ContentHouseActivity.this, "正在上传图片..."); processDailog.show(); super.onPreExecute(); } @Override protected Boolean doInBackground(Void... params) { exceptionContent = ""; sbUrls = new StringBuilder(); if (dataList != null && dataList.size() > 0) { exec = Executors.newFixedThreadPool(4); List<FutureTask<String>> list = new ArrayList<FutureTask<String>>(); uploadPublishHousePicture(list); if (!StringUtils.isNullOrEmpty(sbUrl.toString()) && sbUrl.length() > 0) { sbUrl.deleteCharAt(sbUrl.length() - 1); } exec.shutdown(); if (!StringUtils.isNullOrEmpty(exceptionContent)) { // 表示图片上传失败 mHandler.sendEmptyMessage(5); return false; } } return false; } @Override protected void onPostExecute(Boolean result) { processDailog.dismiss(); if (result != null) {//上传图片成功 if (PhotoUrl != null){ new CommentTask().execute(); } } // else { // toast("抱歉,网络异常"); // } super.onPostExecute(result); } }
/** * 上传房源图片 */ private void uploadPublishHousePicture(List<FutureTask<String>> list) { if (sbUrl.length() > 0) { sbUrl.delete(0, sbUrl.length()); } PhotoUrl = new String[dataList.size()]; for (int i = 0; i < dataList.size(); i++) { if (dataList.get(i).equals("camera_default")) {//清除默认图片 break; } String image = AlbumAndComera .getAlbumPaths(dataList.get(i));//获取系统相册中的图片路径 @SuppressWarnings("unchecked") FutureTask<String> ft = new FutureTask<String>( new GetPicUrl(image));//多线程上传图片 list.add(ft); exec.submit(ft); try { String pic = list.get(i).get(); if (StringUtils.isNullOrEmpty(pic)) {//上传失败 exceptionContent = "图片上传失败"; break; } else {//上传成功 String newUrl = pic.substring(0, pic.lastIndexOf(",")); sbUrl.append(newUrl).append(";"); //添加到数组 PhotoUrl[i] = newUrl; } } catch (Exception e) { exceptionContent = "图片上传失败"; e.printStackTrace(); } } }
/** 上传图片任务*/ @SuppressWarnings("rawtypes") class GetPicUrl implements Callable { private String path; private String name; public GetPicUrl(String path) { this.path = path; } @Override public String call() { try { String url = HttpApi.uploadFile(path); if (url.startsWith("http:")) { return url + "," + name; } } catch (Exception e) { return name; } return name; } }