• Java多线程——<四>让线程有返回值


    一、概述

      到目前为止,我们已经能够声明并使一个线程任务运行起来了。但是遇到一个问题:现在定义的任务都没有任何返回值,那么加入我们希望一个任务运行结束后告诉我一个结果,该结果表名任务执行成功或失败,此时该怎么办呢?

      答案是使用Callable。之前定义的任务都直接实现了Runnable,该接口的run方法并无返回值。而Callable的call方法可以根据你传入的泛型参数返回对应类型的数据。

    二、实现

      1.实现Callable接口,定义可返回结果的线程任务

    复制代码
    public class TaskCallable implements Callable<String>{
        private int id;
        public TaskCallable(int id){
            this.id = id;
        }
        @Override
        public String call() throws Exception {
            
            return "result of taskWithResult "+id;
        }
    }
    复制代码

      注意,泛型参数String表示的是该任务执行之后返回结果的类型。

      2.将该任务交给线程执行者executor,让他来代理执行这些线程

    ExecutorService exec = Executors.newCachedThreadPool();//工头
    ArrayList<Future<String>> results = new ArrayList<Future<String>>();//
    for(int i = 0 ; i < 10 ;i++){
        results.add(exec.submit(new TaskCallable(i)));//submit返回一个Future,代表了即将要返回的结果
    }

      注意,此时需要使用executor的submit方法来调用Callable的call。

      该方法将返回一个Future接口的对象,它的泛型参数代表了call方法要返回的参数类型。

      3.Future类型

      简单的了解了下Future类型:按照名字判断该类型对象代表了线程执行完成后的结果,所以叫Future。那么在获取该类型存放的线程运行结果时,可能该线程并未运行完毕,所以称其为“将来的结果”。

    •   首先,可以用isDone()方法来查询Future是否已经完成,任务完成后,可以调用get()方法来获取结果
    •     如果不加判断直接调用get方法,此时如果线程未完成,get将阻塞,直至结果准备就绪

    从线程中返回数据的两种方法

    1、通过类变量和类方法返回数据

    2、通过回调函数返回数据

    3、实现 Callable<V>接口,其中 V 代表 返回值类型


    一、通过变量和方法返回数据

    先看如下一段代码

    public class MyThread extends Thread
    {
      private String value1;

      private String value2;


      public void run()
      {
      value1 = "value1";
      value2 = "value2";
      }

    public static void main(String[] args)
    {

    MyThread t1 = new MyThread();
    t1.start();
    System.out.println(t1.value1);
    System.out.println(t1.value2);
    }


    }

    输出结果 :

    null
    null
    1
    2
    上面的运行结果很不正常,在run方法中已经对value1和value2进行赋值,但是返回却是null。发生这种情况的原因是: 在调用strat()方法后就立即输出 value1 和 value2 的值,而这里的run 方法 还没有指定到value1 和 value2 赋值语句。

    如果要避免这种情况,就需要等run方法执行完成后才输出 vaue1 和value2 代码。可以考虑使用sleep 将主线程进行延迟,但是有一个问题,你不知道需要延迟多久才能知道 value2 或 value1 有值 !!! 我们可以这样做,如下代码

    public class MyThread extends Thread
    {
    private String value1;

    private String value2;


    public void run()
    {
    value1 = "value1";
    value2 = "value2";
    }

    public static void main(String[] args) throws InterruptedException
    {

    MyThread t1 = new MyThread();
    t1.start();

    while(t1.value1 == null || t1.value1 == null)
    {
    sleep(100);
    }
    System.out.println(t1.value1);
    System.out.println(t1.value2);
    }


    }

    输出结果:

    value1
    value2
    1
    2
    以上方法虽然帮助我们解决了问题,但是Java的线程模型为我们提供了更好的解决方案,就是使用join()方法,join()方法的功能 就是使线程 从异步执行 变成同步执行 。当线程变成同步执行后,就跟普通方法中得到返回数据没什么区别了。

    public static void main(String[] args) throws InterruptedException
    {

    MyThread t1 = new MyThread();
    t1.start();
    t1.join();
    System.out.println(t1.value1);
    System.out.println(t1.value2);
    }

    二、通过回调函数返回数据

    跟 通过回调方法向线程传递 数据的 思路一致

    三、实现 Callable 接口

    1、定义任意类并实现 Callable 接口,并实现 方法 V call() throws Exception。其中,v 皆是代表返回值类型

    2、在 V call() throws Exception 方法里 定义 方法体,并 return 一个返回值

    3、创建线程池,创建任务对象,线程池通过submit(任务对象) 执行任务,并返回一个 Future<V> 对象

    4、通过Future对象.get() 方法获取返回值

    5、关闭线程池,释放资源

    public class MyThread implements Callable<String>
    {

    private String value;

    public MyThread(String value)
    {
    this.value = value;
    }

    public String call() throws Exception
    {

    System.out.println(Thread.currentThread().getName());//pool-1-thread-1
    return "线程返回值是:"+this.value;
    }

    public static void main(String[] args)
    {

    //创建一个线程池对象
    ExecutorService pool = Executors.newCachedThreadPool();

    //创建一个有返回值的任务
    MyThread task = new MyThread("Java");

    //执行任务并获取Future对象
    Future<String> future = pool.submit(task);

    //从 Future 对象 获取任务返回值
    while(true)
    {
    //可以用isDone()方法来查询Future是否已经完成,任务完成后,可以调用get()方法来获取结果
    //注意: 如果不加判断直接调用get方法,此时如果线程未完成,get将阻塞,直至结果准备就绪
    if(future.isDone())
    {
    try
    {

    String returnValue = future.get().toString();

    System.out.println("线程返回值:"+returnValue);


    }catch (Exception e){

    e.printStackTrace();
    }

    //关闭线程池
    pool.shutdown();

    //跳出循环
    break;
    }


    }

    }

    }
    ---------------------
    作者:YFL_iOS
    来源:CSDN
    原文:https://blog.csdn.net/qq_18505715/article/details/78726164
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    C#-WebForm-★★★JQuery-动画★★★
    C#-WebForm-★★★JQuery知识——DOM操作★★★
    C#-WebForm-★★★JQuery知识——基础知识、选择器、事件★★★
    C#-WebForm-组合查询(Queryable延迟查询、Intersect交集)、分页展示基础
    C#-WebForm-★★★LinQ-数据的条件组合查询并进行分页展示(未加各种限定)★★★
    C#-WebForm-光棒效果
    C#-WebForm-LinQ-条件精确查询、高级查询
    C#-WebForm-LinQ(一)-LinQ:语言集成查询(Language Integrated Query)-增删改查、属性扩展
    C#-WebForm JS定时器
    ★★★正则表达式★★★
  • 原文地址:https://www.cnblogs.com/Alex80/p/11123567.html
一二三 - 开发者的网上家园