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("阻塞中**********");
            }
        }
    }
}
相关文章
|
12天前
|
安全 Java 编译器
线程安全问题和锁
本文详细介绍了线程的状态及其转换,包括新建、就绪、等待、超时等待、阻塞和终止状态,并通过示例说明了各状态的特点。接着,文章深入探讨了线程安全问题,分析了多线程环境下变量修改引发的数据异常,并通过使用 `synchronized` 关键字和 `volatile` 解决内存可见性问题。最后,文章讲解了锁的概念,包括同步代码块、同步方法以及 `Lock` 接口,并讨论了死锁现象及其产生的原因与解决方案。
42 10
线程安全问题和锁
|
7天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
25天前
|
数据采集 存储 安全
如何确保Python Queue的线程和进程安全性:使用锁的技巧
本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。
如何确保Python Queue的线程和进程安全性:使用锁的技巧
|
18天前
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
10 0
|
20天前
|
UED 开发工具 iOS开发
Uno Platform大揭秘:如何在你的跨平台应用中,巧妙融入第三方库与服务,一键解锁无限可能,让应用功能飙升,用户体验爆棚!
【8月更文挑战第31天】Uno Platform 让开发者能用同一代码库打造 Windows、iOS、Android、macOS 甚至 Web 的多彩应用。本文介绍如何在 Uno Platform 中集成第三方库和服务,如 Mapbox 或 Google Maps 的 .NET SDK,以增强应用功能并提升用户体验。通过 NuGet 安装所需库,并在 XAML 页面中添加相应控件,即可实现地图等功能。尽管 Uno 平台减少了平台差异,但仍需关注版本兼容性和性能问题,确保应用在多平台上表现一致。掌握正确方法,让跨平台应用更出色。
28 0
|
24天前
|
数据采集 Java Python
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
|
25天前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
49 1
|
8天前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
25 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
10天前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
30 10
|
17天前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。