package com.haizhi.gap.search.offline.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Future<String>> resultList = new ArrayList<>();
//创建10个任务并执行
for (int i = 0; i < 10; i++) {
//使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
Future<String> future = executorService.submit(new TaskWithResult(i));
//将任务执行结果存储到List中
System.out.println("执行结束" + i);
resultList.add(future);
}
System.out.println("有几个返回结果" + resultList.size());
//遍历任务的结果
for (Future<String> fs : resultList) {
try {
//重点: 在executorService提交执行后,如果该线程还未执行完, fs.get()是阻塞的,没有返回结果的,注意,重点内容
//在这里就可以做进度处理,10个进程中,已经有2个处理完成了。
System.out.println(fs.get()); //打印各个线程(任务)执行的结果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
executorService.shutdown();
}
}
}
}
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
public String call() throws Exception {
System.out.println( Thread.currentThread().getName() +" call()方法被自动调用,干活!!!");
//一个模拟耗时的操作
for (int i = 999999; i > 0; i--) ;
return "call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName();
}
}
问题:一个请求的计算任务时间比较长,很有可能在响应时间之内,结果也没有返回。
解决方法:将一个请求分为10个线程去请求,最后将10个线程请求后的结果汇总。怎么将一个请求分为10个线程去请求呢,比如说请求条件是A集合,B集合。请求算法是找出A集合中的元素和B集合中元素的关系。就可能将线程的请求条件变为A中的一个元素和B集合中的一个元素。
在这个解决方法中,遇到一个问题。怎么计算这个任务计算的进度。
解决方法:在处理任务计算进度的时候,根据线程阻塞的时间的不同,每返回一个线程返回结果的时候不同。当线程处理完结果后,将处理完成请求个数加1,统计返回结果的线程数,来除以请求的总数,等到的就是进度了。即在返回对象中定义一个AtomicInteger。在计算进度时,才用定时器定时更新进度。定时器采用Java.Util.Timer来实现。
----------------------- 定时器 Timer的用法 —————————————
现在项目中用到需要定时去检查文件是否更新的功能。timer正好用于此处。
用法很简单,new一个timer,然后写一个timertask的子类即可。
代码如下:
package comz.autoupdatefile;
import java.util.Timer;
import java.util.TimerTask;
public class M {
public static void main(String[] args) {
// TODO todo.generated by zoer
Timer timer = new Timer();
timer.schedule(new MyTask(), 1000, 2000);
}
}
class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("dddd");
}
}
这样,就可以在1秒钟之后开始执行mytask,每两秒钟执行一次。
当然,timer的功能也可以通过自己构造线程,然后在线程中用sleep来模拟停止一段时间,然后再执行某个动作。
其实,看一下timertask的源码就立即可以知道,timertask就是实现了runnable接口的。也就是说,通过timer来间隔一段时间执行一个操作,也是通过一个线程来做到的。