Juc01_多线程概述、四种实现方式、常用方法API、生命周期、买票案例、synchronized锁(二)

简介: ③. Callable接口(创建线程)

③. Callable接口(创建线程)


  • ①. Callable接口中的call方法和Runnable接口中的run方法的区别


  1. 是否有返回值(Runnable接口没有返回值 Callable接口有返回值)


  1. 是否抛异常(Runnable接口不会抛出异常 Callable接口会抛出异常)


  1. 落地方法不一样,一个是call() ,一个是run()


微信图片_20220106173548.png


  • ②. Future接口概述


  1. FutureTask是Future接口的唯一的实现类


  1. FutureTask同时实现了Runnable、Future接口。它既可以作为Runnable被线程执行,又可以作为Futrue得到Callable的返回值


微信图片_20220106173612.png


  /*
  创建线程的方式三: 实现callable接口 ---JDK 5.0 新增
  1.创建一个实现Callable接口的实现类
  2.实现call方法,将此线程需要执行的操作声明在call()中
  3.创建callable接口实现类的对象
  4.将此callable的对象作为参数传入到FutureTask构造器中,创建FutureTask的对象
  5.将FutureTask对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用star
  6.获取callable接口中call方法的返回值
  * */
  public class ThreadNew {
      public static void main(String[] args) {
          //3.创建callable接口实现类的对象
          NumThead m=new NumThead();
          //4.将此callable的对象作为参数传入到FutureTask构造器中,创建FutureTask的对象
          FutureTask futureTask = new FutureTask(m);
          //5.将FutureTask对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
          //FutureTask类继承了Runnable接口
          //new Runnable = futrueTask;
          new Thread(futureTask).start();
          //6.获取callable接口中call方法的返回值
          try {
              //get()方法返回值即为FutureTask构造器参数callable实现类重写的call方法的返回值
              Object sum = futureTask.get();
              System.out.println("总和是:"+sum);
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  }
  //1.创建一个实现Callable接口的实现类
  class  NumThead implements Callable{
     // class  NumThead implements Callable<Integer>{
      //2.实现call方法,将此线程需要执行的操作声明在call()中
      @Override
      public Object call() throws Exception {
      //public Integer call() throws Exception {
          int sum=0;
          for(int i=1;i<=100;i++){
              System.out.println(i);
              sum+=i;
          }
          return sum;
      }
  }


③.FutureTask原理解析


有了Runnable,为什么还要有Callable接口?我们假设一共有四个程序需要执行,第三个程序时间很长 | Runnable接口会按照顺序去执行,会依次从上到下去执行,会等第三个程序执行完毕,才去执行第四个 | Callable接口会把时间长的第三个程序单独开启一个线程去执行,第1、2、4 线程执行不受影响


比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务。子线程就去做其他的事情,过一会儿才去获取子任务的执行结果


微信图片_20220106173642.png


    例子:
  (1). 老师上着课,口渴了,去买水不合适,讲课线程继续,我可以单起个线程找班长帮忙
  买水,水买回来了放桌上,我需要的时候再去get。
  (2). 4个同学,A算1+20,B算21+30,C算31*到40,D算41+50,是不是C的计算量有点大啊,
  FutureTask单起个线程给C计算,我先汇总ABD,最后等C计算完了再汇总C,拿到最终结果
  (3). 高考:会做的先做,不会的放在后面做


  • ④. 注意事项


  1. get( )方法建议放在最后一行,防止线程阻塞(一旦调用了get( )方法,不管是否计算完成都会阻塞)


  1. 一个FutureTask,多个线程调用call( )方法只会调用一次


  1. 如果需要调用call方法多次,则需要多个FutureTask


public class CallableDemo  {
    public static void main(String[] args) throws Exception{
        CallAble c=new CallAble();
        FutureTask<Integer> futureTask=new FutureTask<>(c);
        new Thread(futureTask,"线程A").start();
        new Thread(futureTask,"线程B").start();
        Integer integer = futureTask.get();
        System.out.println("integer = " + integer);
    }
}
class CallAble implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("欢迎你调用call方法");
        return 6;
    }
}


微信图片_20220106173725.png


  • ⑤. isDone()轮询(后面我们会用CompletableFuture来解决get( )阻塞的问题)


  1. 轮询的方式会消耗无畏的CPU资源,而且也不见得能及时地得到计算的结果


  1. 如果想要异步获取结果,通常都会以轮询的方式去获取结果,尽量不要阻塞


public class FutureTaskTest {
    public static void main(String[] args) throws Exception{
        FutureTask futureTask = new FutureTask(()->{
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            System.out.println(Thread.currentThread().getName()+"\t"+"coming......");
            return 1024;
        });
        new Thread(futureTask).start();
        //1.果futureTask.get()放到main线程前面,会导致main线程阻塞
        //Object o = futureTask.get();
        /*Object o = futureTask.get();//不见不散,只要出现了get()方法就会阻塞
        System.out.println("不见不散,只要出现了get()方法就会阻塞,获取到的值为:"+o);*/
        //2.过时不候
//        System.out.println(Thread.currentThread().getName()+"\t"+"线程来了.....");
//        Object o2 = futureTask.get(2L, TimeUnit.SECONDS);
        //3.使用轮询
        while(true){
            if(futureTask.isDone()){
                System.out.println("使用轮询来解决,值为:"+futureTask.get());
                break;
            }else{
                System.out.println("阻塞中**********");
            }
        }
    }
}
相关文章
|
缓存 负载均衡 监控
微服务架构下的电商API接口设计:策略、方法与实战案例
本文探讨了微服务架构下的电商API接口设计,旨在打造高效、灵活与可扩展的电商系统。通过服务拆分(如商品、订单、支付等模块)和标准化设计(RESTful或GraphQL风格),确保接口一致性与易用性。同时,采用缓存策略、负载均衡及限流技术优化性能,并借助Prometheus等工具实现监控与日志管理。微服务架构的优势在于支持敏捷开发、高并发处理和独立部署,满足电商业务快速迭代需求。未来,电商API设计将向智能化与安全化方向发展。
633 102
|
10月前
|
设计模式 消息中间件 安全
【JUC】(3)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
JUC专栏第三篇,带你继续深入JUC! 本篇文章涵盖内容:保护性暂停、生产者与消费者、Park&unPark、线程转换条件、多把锁情况分析、可重入锁、顺序控制 笔记共享!!文章全程干货!
485 1
|
供应链 API
案例分享:API如何助力小型电商实现月销售额翻倍
&quot;悦居生活&quot;通过接入支付、库存、营销及物流API,优化运营流程,解决库存滞后、营销低效、物流体验差等问题,实现库存周转率提升152%、会员复购率增长128%、月销售额突破32万元。
|
并行计算 安全 Java
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
1403 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
XML 网络协议 API
从cURL到GraphQL:不同API类型概述
本文概述了不同API类型及其应用,帮助开发人员选择合适的工具。cURL是强大的命令行工具,适用于调试和自动化;RESTful API基于HTTP方法,适合Web服务和微服务架构;SOAP用于企业级应用,提供高安全性;GraphQL通过精确查询减少数据传输;WebSocket支持实时通信,适用于低延迟场景。了解这些API的特点和优势,有助于构建高效、可扩展的应用程序。
|
存储 搜索推荐 API
淘宝拍立淘按图搜索API接口系列概述
淘宝拍立淘按图搜索API接口允许用户通过上传图片或拍摄实物来搜索相似或相同的商品。这一功能主要依赖于图像识别技术,系统会对上传的图片进行分析和处理,提取出商品的特征信息,并在淘宝的商品数据库中进行匹配搜索,最终返回与上传图片相似或相同的商品列表。
|
JSON 供应链 API
1688寻源通API接口概述
1688寻源通API接口是1688开放平台为采购商提供的商品/供应商搜索与匹配服务接口
|
存储 JSON API
淘宝商品详情API接口概述与JSON数据示例
淘宝商品详情API是淘宝开放平台提供的核心接口之一,为开发者提供了获取商品深度信息的能力。以下是技术细节和示例:
|
JSON 安全 API
淘宝商品详情API接口(item get pro接口概述)
淘宝商品详情API接口旨在帮助开发者获取淘宝商品的详细信息,包括商品标题、描述、价格、库存、销量、评价等。这些信息对于电商企业而言具有极高的价值,可用于商品信息展示、市场分析、价格比较等多种应用场景。
|
数据采集 监控 数据挖掘
常用电商商品数据API接口(item get)概述,数据分析以及上货
电商商品数据API接口(item get)是电商平台上用于提供商品详细信息的接口。这些接口允许开发者或系统以编程方式获取商品的详细信息,包括但不限于商品的标题、价格、库存、图片、销量、规格参数、用户评价等。这些信息对于电商业务来说至关重要,是商品数据分析、价格监控、上货策略制定等工作的基础。