Thread之FutureTask

FutureTask

FutureTask扩展了接口Runnable和Future,因此它可以作为Runnable用于Executor.submit(),也可以直接进行FutureTask.run()。FutureTask的构造函数可以使用Callable进行构造。FutureTask主要用于在多线程下,一个线程需要等待另外一个线程将某项任务执行完毕后才能继续执行。

编程模型

protected final ConcurrentHashMap<String, Future<String>> taskQueue = 
						new ConcurrentHashMap<>();
private String executeTask(final String taskName) {
	while (true) {
		Future<String> future = taskQueue.get(taskName); // 1.1和2.1 获取任务
		if (future == null) {
			Callable<String> task = new Callable<>() {
				@Override
				public String call() {
					// 业务逻辑处理,此处经过处理后返回一个字符串
				}
			};
			FutureTask<String> futureTask = new FutureTask<>(task); // 1.2创建任务
			future = taskQueue.putIfAbsent(taskName, futureTask); // 1.3将任务入列
			if (future == null) {
				future = futureTask; // 1.4执行任务
				futureTask.run();
			}	
		}
		try {
			return future.get(); // 1.5和2.2 线程在此阻塞等待任务完成执行
		} catch (InterruptedException ex) {
			taskQueue.remove(taskName);
		}
	}
}

线程1和线程2并发执行上述代码,线程1从1.1处取出任务为空,执行代码直到1.4,开始执行任务,在1.5处阻塞等待,线程2在2.1处取出了同一名称的非空任务,在2.2处阻塞等待任务被完成执行。

实例

并发的多个线程不断从taskQueue中获取对应taskName的任务,假设线程Thread-A刚开始没有取得任务(即任务为空),于是创建新任务,并将其放入并发队列中,等待任务执行(FutureTask.run())完毕后,利用阻塞方法Future.get()获取结果。Thread-B执行相同名称的任务,因此在Thread-1执行到阻塞方法时,Thread-B从并发队列中获取了非空的任务,因而Thread-B也在Future.get()方法处等待任务执行完毕。实例中采用随机数方法获取最多10不同名称的taskName,因此必然有线程获取同样名称任务,确保了有线程在阻塞方法future.get()处等待。

package pool;

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;

public class FutureTaskTest {
	private static ConcurrentHashMap<String, Future<String>> taskCache = new ConcurrentHashMap<String, Future<String>>();
	private static final String TASK_NAME_PREFIX = "future_task_test";

	private static void executeTask(final String taskName) {
		Future<String> future = taskCache.get(taskName);
		if (future == null) {
			Callable<String> callable = new Callable<String>() {
				@Override
				public String call() throws Exception {
					return taskName;
				}
			};
			FutureTask<String> futureTask = new FutureTask<String>(callable);
			future = taskCache.putIfAbsent(taskName, futureTask);
			if (future == null) {
				future = futureTask;
				System.out.println(Thread.currentThread().getName() + ": run");
				futureTask.run();
			}
		}

		try {
			Thread.sleep(1000);
			System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + ": " + future.get());
		} catch (InterruptedException | ExecutionException e) {
			taskCache.remove(taskName);
		}
	}

	public static void main(String[] args) {
		int count = 0;
		while (true) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					executeTask(TASK_NAME_PREFIX + (int) (Math.random() * 10)); //确保任务名称流水号不超过10个
				}
			}, "Thread-" + (count++)).start();
			// 控制线程数量
			if (count > 50) 
				break;
		}
	}
}

测试结果如下,确实只有10个线程新建了任务,其余线程分别等待这10个线程执行完成任务后,继续执行。

time         threadname  type  taskname
1537429412843 Thread-0: RUN future_task_test1
1537429412844 Thread-9: RUN future_task_test6
1537429412843 Thread-6: RUN future_task_test4
1537429412843 Thread-1: RUN future_task_test2
1537429412844 Thread-8: RUN future_task_test9
1537429412844 Thread-4: RUN future_task_test3
1537429412844 Thread-10: RUN future_task_test0
1537429412844 Thread-11: RUN future_task_test8
1537429412845 Thread-20: RUN future_task_test7
1537429412846 Thread-23: RUN future_task_test5
1537429413847 Thread-2: GET future_task_test1
1537429413847 Thread-6: GET future_task_test4
1537429413848 Thread-13: GET future_task_test1
1537429413848 Thread-19: GET future_task_test1
1537429413848 Thread-20: GET future_task_test7
1537429413849 Thread-25: GET future_task_test9
1537429413849 Thread-27: GET future_task_test4
1537429413849 Thread-5: GET future_task_test9
1537429413849 Thread-32: GET future_task_test9
1537429413849 Thread-36: GET future_task_test5
1537429413850 Thread-39: GET future_task_test3
1537429413850 Thread-42: GET future_task_test5
1537429413850 Thread-45: GET future_task_test6
1537429413850 Thread-41: GET future_task_test4
1537429413847 Thread-8: GET future_task_test9
1537429413847 Thread-1: GET future_task_test2
1537429413847 Thread-3: GET future_task_test9
1537429413847 Thread-9: GET future_task_test6
1537429413847 Thread-0: GET future_task_test1
1537429413850 Thread-38: GET future_task_test1
1537429413850 Thread-46: GET future_task_test9
1537429413848 Thread-18: GET future_task_test8
1537429413850 Thread-43: GET future_task_test7
1537429413850 Thread-44: GET future_task_test2
1537429413850 Thread-40: GET future_task_test7
1537429413850 Thread-12: GET future_task_test8
1537429413849 Thread-14: GET future_task_test4
1537429413849 Thread-37: GET future_task_test3
1537429413849 Thread-35: GET future_task_test7
1537429413849 Thread-31: GET future_task_test3
1537429413849 Thread-33: GET future_task_test6
1537429413849 Thread-34: GET future_task_test8
1537429413849 Thread-30: GET future_task_test5
1537429413849 Thread-7: GET future_task_test1
1537429413849 Thread-29: GET future_task_test4
1537429413849 Thread-28: GET future_task_test9
1537429413849 Thread-24: GET future_task_test5
1537429413849 Thread-26: GET future_task_test5
1537429413849 Thread-22: GET future_task_test1
1537429413849 Thread-23: GET future_task_test5
1537429413849 Thread-21: GET future_task_test2
1537429413848 Thread-16: GET future_task_test3
1537429413848 Thread-17: GET future_task_test0
1537429413848 Thread-11: GET future_task_test8
1537429413848 Thread-15: GET future_task_test2
1537429413847 Thread-4: GET future_task_test3
1537429413847 Thread-10: GET future_task_test0
1537429413854 Thread-48: GET future_task_test1
1537429413854 Thread-50: GET future_task_test2
1537429413854 Thread-49: GET future_task_test3
1537429413854 Thread-47: GET future_task_test1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值