public String costTime() {
try {
// 模拟RealData耗时操作
Thread.sleep(1000L);
return "result";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "exception";
}
}
通过Future实现
与上述FutureTask不同的是, RealData需要实现Callable接口.
public class FutureDemo2 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService service = Executors.newCachedThreadPool();
Future<String> future = service.submit(new RealData2());
System.out.println("RealData2方法调用完毕");
// 模拟主函数中其他耗时操作
doOtherThing();
// 获取RealData2方法的结果
System.out.println(future.get());
}
private static void doOtherThing() throws InterruptedException {
Thread.sleep(2000L);
}
}
class RealData2 implements Callable<String>{
public String costTime() {
try {
// 模拟RealData耗时操作
Thread.sleep(1000L);
return "result";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "exception";
}
@Override
public String call() throws Exception {
return costTime();
}
}
另外Future本身还提供了一些额外的简单控制功能, 其API如下
// 取消任务
boolean cancel(boolean mayInterruptIfRunning);
// 是否已经取消
boolean isCancelled();
// 是否已经完成
boolean isDone();
// 取得返回对象
V get() throws InterruptedException, ExecutionException;
// 取得返回对象, 并可以设置超时时间
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
生产者-消费者模式是一个经典的多线程设计模式. 它为多线程间的协作提供了良好的解决方案。
在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程。
生产者线程负责提交用户请求,消费者线程则负责具体处理生产者提交的任务。
生产者和消费者之间则通过共享内存缓冲区进行通信, 其结构图如下
PCData为我们需要处理的元数据模型, 生产者构建PCData, 并放入缓冲队列.
消费者从缓冲队列中获取数据, 并执行计算.
生产者核心代码
while(isRunning) {
Thread.sleep(r.nextInt(SLEEP_TIME));
data = new PCData(count.incrementAndGet);
// 构造任务数据
System.out.println(data + " is put into queue");
if (!queue.offer(data, 2, TimeUnit.SECONDS)) {
// 将数据放入队列缓冲区中
System.out.println("faild to put data : " + data);
}
}
消费者核心代码
while (true) {
PCData data = queue.take();
// 提取任务
if (data != null) {
// 获取数据, 执行计算操作
int re = data.getData() * 10;
System.out.println("after cal, value is : " + re);
Thread.sleep(r.nextInt(SLEEP_TIME));
}
}
生产消费者模式可以有效对数据解耦, 优化系统结构.
降低生产者和消费者线程相互之间的依赖与性能要求.
一般使用BlockingQueue作为数据缓冲队列, 他是通过锁和阻塞来实现数据之间的同步,
如果对缓冲队列有性能要求, 则可以使用基于CAS无锁设计的ConcurrentLinkedQueue.
分而治之严格来讲, 分而治之不算一种模式, 而是一种思想.
它可以将一个大任务拆解为若干个小任务并行执行, 提高系统吞吐量.
我们主要讲两个场景, Master-Worker模式, ForkJoin线程池.
Master-Worker模式该模式核心思想是系统由两类进行协助工作: Master进程, Worker进程.
Master负责接收与分配任务, Worker负责处理任务. 当各个Worker处理完成后,
将结果返回给Master进行归纳与总结.
假设一个场景, 需要计算100个任务, 并对结果求和, Master持有10个子进程.
Master代码