多线程九 线程池之Future接口
发布日期:2022-04-11 08:52:49 浏览次数:4 分类:技术文章

本文共 4261 字,大约阅读时间需要 14 分钟。

线程池之Future接口

1. Future

Future接口中的get()会阻塞当前线程直到取得Callable的返回值

API文档

FutureTask 类是实现 Future ,实现 Runnable ,所以可以由 Executor 执行

FutureTask 可用于包装 Callable 或 Runnable 对象. 因为 FutureTask 实现 Runnable ,一个FutureTask可以提交到一个Executor执行

在这里插入图片描述

要想讲的清楚多线程,怎么能少得了我们的12306呢?今天,又是卖火车票的一天…
在这里插入图片描述
在这里插入图片描述

package com.ThreadPool;import java.util.concurrent.*;/** * @Author: Mr.Q * @Date: 2019-08-05 09:02 * @Description: */class CallableThread implements Callable
{
private Integer tickets = 30; @Override public String call() throws Exception {
for (int i = 0; i < tickets; i++) {
if(tickets > 0) {
System.out.println(Thread.currentThread().getName() +"还剩 "+tickets--+" 票..."); } } return Thread.currentThread().getName() + "票卖完了!"; }}public class FutureTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 线程池创建线程 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,5, 60,TimeUnit.SECONDS, new LinkedBlockingDeque
()); CallableThread callableThread = new CallableThread(); // Future接口接收 Callable的返回值 Future
future = null; for (int i = 0; i < 5; i++) {
// submit()提交需要返回值的任务 future = threadPoolExecutor.submit(callableThread); } //----------------- main - --------------- System.out.println(future.get()); threadPoolExecutor.shutdown(); }}

get()会阻塞当前线程直到取得Callable的返回值

此时,在main()中调用get(),导致当前线程(主线程)阻塞,直到线程池中的子线程执行完毕后,在执行!

若此时我们把 get() 放在提交线程任务时调用

Future
future = null; // 单线程模式 get()会阻塞当前线程,直到有返回值为止 for (int i = 0; i < 5; i++) {
Future
future0 = threadPoolExecutor.submit(callableThread); System.out.println(future0.get()); }

那么此时阻塞当前提交任务的线程,也就是说,它没有提交完任务,其他的线程都不能执行,都得等着. 表面上看我们在最大池中创建了5个线程,可实际上执行任务的只有一个,其他的都在阻塞. 此时为 单线程模式

2. FutureTask

FutureTask : 可以保证在多线程场景下,任务只会被一个线程执行,其他线程不再执行此任务;

在多线程并发下可以保证任务(传入的CallableRunnable)只执行一次

什么意思呢? 就是我现在要给在火车站柜台买票的每一个人,买一张票,我就请他去候车室喝咖啡(虽然这是不可能的)

如果,我让一个乘务员来做这件事(把乘务员抽象的看作是一个线程),他先得乘客卖票,然后再给乘客到候车室冲咖啡递上去,是不是很麻烦,效率很低?这要是到春运了,估计回家了,也就开学了…

那我再雇一个乘务员,一个负责卖票,另一个负责在候车室服务乘客,效率高,分工明确.

在这里插入图片描述

那么此时再看我们FutureTask的作用

可以保证在多线程场景下,任务只会被一个线程执行,其他线程不再执行此任务

相当于负责售票的乘务员A不管服务乘客,负责服务乘客的乘务员B不管卖票;

而开始的时候,这两件事情都由乘务员C来负责,两个任务都得执行.

这就是FutureTask的应用场景

在这里插入图片描述

最近也没怎么敲代码,但是头发却是哗哗的往下掉呀. 养生与学习并重,少熬夜,多运动. 然后,没事的时候,少喝点肥仔快乐水,多喝茶养生.

那我们就用FutureTask来实现一下泡茶的场景吧

在这里插入图片描述现在,两个线程负责不同的任务,并且有一个线程在执行任务后,其他线程就不再执行任务

import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;import java.util.concurrent.TimeUnit;/** * @Author: Mr.Q * @Date: 2019-08-07 09:17 * @Description: */// 线程1任务class StepOne implements Callable
{
private FutureTask
futureTask; public StepOne(FutureTask
futureTask) {
this.futureTask = futureTask; } @Override public String call() throws Exception {
System.out.println("T1:洗水壶."); TimeUnit.SECONDS.sleep(1); System.out.println("T1:烧开水.."); TimeUnit.SECONDS.sleep(10); System.out.println("T1:等待茶叶..."); // 线程1阻塞到此处一直等到线程2返回为止 String str = futureTask.get(); System.out.println("T1:拿到茶叶...."); System.out.println("泡茶"); return "上茶~~~"; }}// 线程2任务class StepTwo implements Callable
{
@Override public String call() throws Exception {
System.out.println("T2:洗茶壶*"); TimeUnit.SECONDS.sleep(1); System.out.println("T2:洗茶杯**"); TimeUnit.SECONDS.sleep(1); System.out.println("T2:拿茶叶***"); TimeUnit.SECONDS.sleep(3); return "龙井"; }}public class FutureThreadPoolDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask step2 = new FutureTask(new StepTwo()); //将线程2的龙井茶传给线程1 FutureTask step1 = new FutureTask(new StepOne(step2)); new Thread(step1).start(); new Thread(step2).start(); // 主线程在step1,step2执行完之后再执行 System.out.println(step1.get()); }}

执行过程:

在这里插入图片描述
好了,今天的养生课到这里就结束了,下课吧同学们…

转载地址:https://iqqcode.blog.csdn.net/article/details/99226671 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:多线程买票案例
下一篇:多线程之间通信及线程池

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年03月31日 09时14分13秒