同样还是工作中用到的ExecutorService这个线程池。
多线程这块一直在我印象里就是一个难缠的家伙。自己本来也是新手
还用了ExecutorService这个类,所以不用想,给我带来了很大的麻烦。ExecutorService这个从API查得好像有三种模式。具体的
我也就不多少有什么区别了,因为我也搞不清。最终我选择了Executors.newFixedThreadPool(10); 这个是生成一个固定线程数
的线程池,在这里我就定义了一个只能容纳10个线程的线程池。
那么定义好了怎么用呢,看看代码吧:
int pageDownloaderPoolNumber =10;
public static ExecutorService pageDownloaderPool = Executors.newFixedThreadPool(pageDownloaderPoolNumber);
首先定义好pageDownloaderPool,最大线程数为10。
crawlerFactory cf = new crawlerFactory(crawler); // 此处为new一个线程对象,因为在线程池中放的任务必须是一个线程类的对象
即继承了Runnable接口或其他某某的类的对象。
pageFutureList.add(pageDownloaderPool.submit(cf));//此处是将线程任务放进线程池中执行。注意,因为该线程池可以返回
一个任务队列。所以我们要定义一个FutureList来获得这些任务队列:
public static List<Future> pageFutureList = new ArrayList<Future>(pageDownloaderPoolNumber);
这样线程池里的任务就启动了,但要记住,如果你有30个线程同时启动,那么最多有10个在工作,同时还得对任务队列进行管理
特别是pageFutureList.add(pageDownloaderPool.submit(cf));这个在循环中的话一定要加上控制:
while(){
----------
hasFreeThread(pageFutureList);
if(pageFutureList.size() < pageDownloaderPoolNumber){
pageFutureList.add(pageDownloaderPool.submit(cf));
}
}
同时有这么一个方法去检测队列是否有空闲的:
public static boolean hasFreeThread(List<Future> list){
synchronized (list) {
if(list.size() == 0){
return true;
}
Future finishedFuture = null;
try{
for (Future temp : list) {
if(temp.isDone()/* || temp.get() == null*/){
finishedFuture = temp;
return true;
}
}
}catch(Exception e){
e.printStackTrace();
return false;
}finally{
if(finishedFuture != null){
list.remove(finishedFuture);
}
}
return false;
}
}
这样的话任务队列中就保持着永远最大数是10,当完成一个任务变成9后,下次就再加入一个任何到队列,就避免了线程的阻塞