线程池的简单使用
Posted 魏军强
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池的简单使用相关的知识,希望对你有一定的参考价值。
需求:
最近有个需求,要求把网页中的图片地址和音频地址抓出来,然后下载保存到本地。这里一个网页中有可能有一个url地址,也有可能有多个个url地址。当然,下载这种操作,另外下载超过1个,想到的就是用线程池。
实现:
第一步:先写一个ThreadPoolProxyFactory ,里面提供下载的线程池。代码如下:
/**
* @author weijunqiang
* @date 2018/7/20
* 一个ThreadPoolProxyFactory ,里面提供下载的线程池
*/
public class ThreadPoolProxyFactory
static ThreadPoolProxy mDownLoadThreadPoolProxy;
/**
* 得到下载线程池代理对象mDownLoadThreadPoolProxy
*/
public static ThreadPoolProxy getDownLoadThreadPoolProxy()
if (mDownLoadThreadPoolProxy == null)
synchronized (ThreadPoolProxyFactory.class)
if (mDownLoadThreadPoolProxy == null)
mDownLoadThreadPoolProxy = new ThreadPoolProxy(3, 20);
return mDownLoadThreadPoolProxy;
第二步:写一个线程池代理,替线程池完成一些操作。提供了三种方法:执行任务,提交任务,移除任务。
/**
* @author weijunqiang
* @date 2018/7/20
* 线程池代理,替线程池完成一些操作。提供了三种方法:执行任务,提交任务,移除任务。
*/
public class ThreadPoolProxy
ThreadPoolExecutor mExecutor;
private int mCorePoolSize;
private int mMaximumPoolSize;
/**
* @param corePoolSize 核心池的大小
* @param maximumPoolSize 最大线程数
*/
public ThreadPoolProxy(int corePoolSize, int maximumPoolSize)
mCorePoolSize = corePoolSize;
mMaximumPoolSize = maximumPoolSize;
/**
* 初始化ThreadPoolExecutor
* 双重检查加锁,只有在第一次实例化的时候才启用同步机制,提高了性能
*/
private void initThreadPoolExecutor()
if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated())
synchronized (ThreadPoolProxy.class)
if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated())
long keepAliveTime = 3000;
TimeUnit unit = TimeUnit.MILLISECONDS;
BlockingQueue workQueue = new LinkedBlockingDeque<>();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
mExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, handler);
/**
执行任务和提交任务的区别?
1.有无返回值
execute->没有返回值
submit-->有返回值
2.Future的具体作用?
1.有方法可以接收一个任务执行完成之后的结果,其实就是get方法,get方法是一个阻塞方法
2.get方法的签名抛出了异常===>可以处理任务执行过程中可能遇到的异常
*/
/**
* 执行任务
*/
public void execute(Runnable task)
initThreadPoolExecutor();
mExecutor.execute(task);
/**
* 提交任务
* Runnable
*/
public Future submit(Runnable task)
initThreadPoolExecutor();
return mExecutor.submit(task);
/**
* 提交任务
* Callable能接受一个泛型,然后在call方法中返回一个这个类型的值。而Runnable的run方法没有返回值
* Callable的call方法可以抛出异常,而Runnable的run方法不会抛出异常。
*/
public Future<ImgCacheBean> submit(Callable<ImgCacheBean> callable)
initThreadPoolExecutor();
return mExecutor.submit(callable);
/**
* 移除任务
*/
public void remove(Runnable task)
initThreadPoolExecutor();
mExecutor.remove(task);
第三步:线程池的使用
private void startDownloads(final List<ImgCacheBean> urls)
try
final List<Future<ImgCacheBean>> result = new ArrayList<>();
for (int i = 0; i < urls.size(); i++)
String cacheUrl = "";
String fileName = "";
//TODO 将url中的汉字进行转码,空格换成"%20"
String gradeChineseStr = RegularUtils.getChinese(urls.get(i).getHttpUrl());
cacheUrl = decodeSrc.replace(" ", "%20");
URL url = new URL(cacheUrl);
Future<ImgCacheBean> future = ThreadPoolProxyFactory.getDownLoadThreadPoolProxy().submit(new DoCallable(url, urls.get(i), fileName));
result.add(future);
//TODO 这里面使用又起一个线程,是因为Future的get()方法是一个阻塞方法,不能在主线程直接使用
new Thread()
@Override
public void run()
super.run();
try
for (int k = 0; k < result.size(); k++)
//TODO get(6, TimeUnit.SECONDS)单个文件最长等6秒
ImgCacheBean imgCacheBean = result.get(k).get(6, TimeUnit.SECONDS);
if (imgCacheBean != null)
downloads.add(imgCacheBean);
if (downloads.size() >= urls.size())
Message msg = mHandle.obtainMessage();
msg.what = 1;
mHandle.sendMessage(msg);
catch (Exception e)
e.printStackTrace();
Message msg = mHandle.obtainMessage();
msg.what = 2;
mHandle.sendMessage(msg);
.start();
catch (Exception e)
e.printStackTrace();
initWebview();
总结:
上面第三个使用方法,只是是部分代码,在使用的时候需要注意,在线程池调用了submit(Callable<ImgCacheBean> callable)
之后,该方法会立刻返回一个Future<ImgCacheBean> future
对象。但它并不代表Callable代表的任务已经执行完了。Callable代表的任务执行没执行完是不知道的。具体体现在Future的get()方法是一个阻塞方法。当调用Future的get()方法后,直到Callable的call方法执行完后或者抛出异常才返回结果(这个过程可能很长时间,所以使用了get(6, TimeUnit.SECONDS)方法,表示最多等6秒)。所以上述在获取future对象返回的结果时,将它另起线程处理,等有了结果再通知主线程结果。
以上是关于线程池的简单使用的主要内容,如果未能解决你的问题,请参考以下文章