icode icode
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

iqqcode

保持对技术的探索实践与热爱
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaSE

    • 面向对象

    • 常用API

    • 集合类

    • 多线程

      • Thread

      • JUC

        • JUC包下的常用工具类
        • JUC包下常用的辅助类
        • 阻塞队列,同步队列
        • Java内存模型JMM详解
        • volatile
        • CAS自旋
        • CAS与volatile无锁解决并发
        • AQS
        • 线程池
        • Future接口
      • JDK8新特性

      • IO流

      • JVM

    • JavaWeb

    • JavaEE

    • JavaTopic

    • 设计模式

    • 计算机基础

    • Java后端
    • JavaSE
    • 多线程
    • JUC
    iqqcode
    2021-06-17
    目录

    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<String> {
        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<Runnable>());
    
            CallableThread callableThread = new CallableThread();
            // Future接口接收 Callable的返回值
            Future<String> future = null;
            for (int i = 0; i < 5; i++) {
            // submit()提交需要返回值的任务
                 future = threadPoolExecutor.submit(callableThread);
            }
            //----------------- main - ---------------
            System.out.println(future.get());
            threadPoolExecutor.shutdown();
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42

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

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

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

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

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

    # 2. FutureTask

    FutureTask : 可以保证在多线程场景下,任务只会被一个线程执行,其他线程不再执行此任务;
    在多线程并发下可以保证任务(传入的Callable 或 Runnable)只执行一次

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

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

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

    在这里插入图片描述

    那么此时再看我们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<String> {
        private FutureTask<String> futureTask;
    
        public StepOne(FutureTask<String> 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<String> {
    
        @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());
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59

    执行过程:

    在这里插入图片描述

    好了,今天的养生课到这里就结束了,下课吧同学们...

    编辑 (opens new window)
    上次更新: 2021/06/27, 10:49:09
    线程池
    Lambda表达式

    ← 线程池 Lambda表达式→

    最近更新
    01
    匿名内部类
    10-08
    02
    函数式接口
    10-08
    03
    ARouter-Kotlin踩坑
    10-05
    更多文章>
    Theme by Vdoing | Copyright © 2021-2023 iqqcode | MIT License | 备案号-京ICP备2021028793号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×