浅谈Java获得多线程的返回结果方式(3种)

一:Java创建线程方式

继承Thread类或者实现Runnable接口。
但是Runnable 的 run() 方法是不带返回值的,那如果我们需要一个耗时任务在执行完之后给予返回值,应该怎么做呢?

第一种方法:在 Runnable 的实现类中设置一个变量 V,在 run 方法中将其改变为我们期待的结果,然后通过一个 getV() 方法将这个变量返回。

package com.test.thread;

import java.util.*;
import sun.swing.AccumulativeRunnable;
//获得线程的返回结果方式一
/*
 *在runnable实现类中设置一个变量x,在run方法中将其改变为我们期待的结果,然后通过一个getX()方法将这个变量返回
 */
public class RunnableTest {
 public static void main(String[] args) throws Exception {
  System.out.println("使用Runnable获取返回结果");
  List<Thread> workers = new ArrayList<>(10);
  List<RunnableAcction> tasks = new ArrayList<>(10);
  //创建10个线程,每个线程分别负责累加1-10,11-20,.........,91-100
  for(int i=0;i<10;i++) {
  RunnableAcction task = new RunnableAcction(i*10+1,(i+1)*10);
  Thread work = new Thread(task,"累加器线程"+i);
  workers.add(work);
  tasks.add(task);
  work.start();
  }
  int total = 0;
  for(int i = 0;i<workers.size();i++) {
  workers.get(i).join();
  total += tasks.get(i).getResult();
  }
  System.out.println("\n累加的结果:"+total);
 }

 static final class RunnableAcction implements Runnable{

  private int a;
  public RunnableAcction(int a, int b) {
  super();
  this.a = a;
  this.b = b;
  }
  private int b;
  private int result;
  @Override
  public void run() {
  result = 0;
  try {
   for(int i=a;i<= b;i++) {
   result += i;
   Thread.sleep(100);
   }
  } catch (Exception e) {
   // TODO: handle exception
  }
  System.out.printf("(%s) - 运行结束,结果为 %d\n",Thread.currentThread().getName(),result);
  }
    public int getResult() {//获取线程返回结果
       return result;
    }
 }
}

第二种方法:使用 Callable 和 FutureTask。

使用 FutureTask 的过程如下:
(1)通过一个 Callable 任务或者一个 Runnable(一开始就指定 result)任务构造 FutureTask;
(2)将 FutureTask 交给 Thread 去运行;
(3)使用 FutureTask 的 get 方法(或者 Thread 的 join 方法)阻塞当前线程直到获得任务的结果。

import java.util.*;
import java.util.concurrent.*;

public class CallableTest {

  public static void main(String[] args) throws Exception {
    System.out.println("使用 Callable 获得返回结果:");

    List<FutureTask<Integer>> futureTasks = new ArrayList<>(10);
    // 新建 10 个线程,每个线程分别负责累加 1~10, 11~20, ..., 91~100
    for (int i = 0; i < 10; i++) {
      AccumCallable task = new AccumCallable(i * 10 + 1, (i + 1) * 10);
      FutureTask<Integer> futureTask = new FutureTask<>(task);
      futureTasks.add(futureTask);
      Thread worker = new Thread(futureTask, "慢速累加器线程" + i);
      worker.start();
    }

    int total = 0;
    for (FutureTask<Integer> futureTask : futureTasks) {
      total += futureTask.get(); // get() 方法会阻塞直到获得结果
    }
    System.out.println("累加的结果: " + total);
  }

  static final class AccumCallable implements Callable<Integer> {

    private final int begin;
    private final int end;

    public AccumCallable(int begin, int end) {
      this.begin = begin;
      this.end = end;
    }

    @Override
    public Integer call() throws Exception {
      int result = 0;
      for (int i = begin; i <= end; i++) {
        result += i;
        Thread.sleep(100);
      }
      System.out.printf("(%s) - 运行结束,结果为 %d\n",
      Thread.currentThread().getName(), result);
      return result;
    }
  }
}

二:FutureTask介绍

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果。因此,**FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。**另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

一个FutureTask 可以用来包装一个 Callable 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以一个 FutureTask可以提交(submit)给一个Excutor执行(excution)。

FutureTask执行多任务计算的使用场景:

利用FutureTask和ExecutorService,可以用多线程的方式提交计算任务,主线程继续执行其他任务,当主线程需要子线程的计算结果时,再异步获取子线程的执行结果。

import java.util.*;
import java.util.concurrent.*;

public class FutureTest1 {

  public static void main(String[] args) {

    Task task = new Task();// 新建异步任务,然后执行futureTask
    FutureTask<Integer> future = new FutureTask<Integer>(task) {
      // 异步任务执行完成,回调
      @Override
      protected void done() {
        try {
          System.out.println("future.done():" + get());
        } catch (InterruptedException e) {
          e.printStackTrace();
        } catch (ExecutionException e) {
          e.printStackTrace();
        }
      }
    };
    // 创建线程池(使用了预定义的配置)
    ExecutorService executor = Executors.newCachedThreadPool();
    executor.execute(future);

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e1) {
      e1.printStackTrace();
    }
    // 可以取消异步任务
    // future.cancel(true);

    try {
      // 阻塞,等待异步任务执行完毕-获取异步任务的返回值
      System.out.println("future.get():" + future.get());
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
  }

  // 异步任务
  static class Task implements Callable<Integer> {
    // 返回异步任务的执行结果
    @Override
    public Integer call() throws Exception {
      int i = 0;
      for (; i < 10; i++) {
        try {
          System.out.println("异步任务:"+Thread.currentThread().getName() + "_"              + i);
          Thread.sleep(500);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      return i;
    }
  }
}

参考文章:
https://blog.csdn.net/chenliguan/article/details/54345993
https://blog.csdn.net/linchunquan/article/details/22382487
https://segmentfault.com/a/1190000007767231

到此这篇关于浅谈Java获得多线程的返回结果方式的文章就介绍到这了,更多相关Java 多线程的返回结果内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java多线程编程之从线程返回数据的两种方法

    一.通过类变量和方法返回数据 使用这种方法返回数据需要在调用start方法后才能通过类变量或方法得到数据.让我们先来看看例程2-13会得到什么结果. 复制代码 代码如下: package mythread; public class MyThread extends Thread{    private String value1;    private String value2; public void run()    {        value1 = "通过成员变量返回数据"

  • java多线程返回值使用示例(callable与futuretask)

    Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值,下面来看一个简单的例子 复制代码 代码如下: package com.future.test; import java.io.FileNotFoundException;import java.io.IOException;i

  • 浅谈Java获得多线程的返回结果方式(3种)

    一:Java创建线程方式 继承Thread类或者实现Runnable接口. 但是Runnable 的 run() 方法是不带返回值的,那如果我们需要一个耗时任务在执行完之后给予返回值,应该怎么做呢? 第一种方法:在 Runnable 的实现类中设置一个变量 V,在 run 方法中将其改变为我们期待的结果,然后通过一个 getV() 方法将这个变量返回. package com.test.thread; import java.util.*; import sun.swing.Accumulati

  • 浅谈java调用Restful API接口的方式

    摘要:最近有一个需求,为客户提供一些RestfulAPI接口,QA使用postman进行测试,但是postman的测试接口与java调用的相似但并不相同,于是想自己写一个程序去测试RestfulAPI接口,由于使用的是HTTPS,所以还要考虑到对于HTTPS的处理.由于我也是首次使用Java调用restful接口,所以还要研究一番,自然也是查阅了一些资料. 分析:这个问题与模块之间的调用不同,比如我有两个模块frontend和backend,frontend提供前台展示,backend提供数据支

  • 浅谈java中对集合对象list的几种循环访问

    java中对集合对象list的几种循环访问的总结如下  1 经典的for循环 public static void main(String[] args) { List<String> list = new ArrayList(); list.add("123"); list.add("java"); list.add("j2ee"); System.out.println("=========经典的for循环=======

  • 浅谈java对象之间相互转化的多种方式

    第一种:使用org.apache.commons.beanutils.PropertyUtils.copyProperties()拷贝一个bean中的属性到另一个bean中,第一个参数是目标bean,第二个参数是源bean. 特点: 1.它的性能问题相当差 2.PropertyUtils有自动类型转换功能,而java.util.Date恰恰是其不支持的类型 3.PropertyUtils支持为null的场景: public static void copyProperties(Object de

  • 浅谈java中HashMap键的比较方式

    先看一个例子 Integer integer=12344; Integer integer1=12344; 在Java中Integer 和Integer1是不相等的,但是如果再执行如下语句 map.put(integer, 1); map.put(integer1, 2); 会发现2会把1覆盖,问题来了,明明是两个不同的对象,为什么,2会把1覆盖呢? 我们看HashMap中添加键的源代码,如下 可以发现我们传进来的键交给了一个hash的成员方法区处理,这里我们看看hash方法的源码 哦,看到这里

  • 浅谈Java多线程处理中Future的妙用(附源码)

    java 中Future是一个未来对象,里面保存这线程处理结果,它像一个提货凭证,拿着它你可以随时去提取结果.在两种情况下,离开Future几乎很难办.一种情况是拆分订单,比如你的应用收到一个批量订单,此时如果要求最快的处理订单,那么需要并发处理,并发的结果如果收集,这个问题如果自己去编程将非常繁琐,此时可以使用CompletionService解决这个问题.CompletionService将Future收集到一个队列里,可以按结果处理完成的先后顺序进队.另外一种情况是,如果你需要并发去查询一

  • 浅谈java中异步多线程超时导致的服务异常

    在项目中为了提高大并发量时的性能稳定性,经常会使用到线程池来做多线程异步操作,多线程有2种,一种是实现runnable接口,这种没有返回值,一种是实现Callable接口,这种有返回值. 当其中一个线程超时的时候,理论上应该不 影响其他线程的执行结果,但是在项目中出现的问题表明一个线程阻塞,其他线程返回的接口都为空.其实是个很简单的问题,但是由于第一次碰到,还是想了一些时间的.很简单,就是因为阻塞的那个线 程没有释放,并发量一大,线程池数量就满了,所以其他线程都处于等待状态. 附上一段自己写的调

  • 浅谈Java多线程的优点及代码示例

    尽管面临很多挑战,多线程有一些优点使得它一直被使用.这些优点是: 资源利用率更好 程序设计在某些情况下更简单 程序响应更快 资源利用率更好 想象一下,一个应用程序需要从本地文件系统中读取和处理文件的情景.比方说,从磁盘读取一个文件需要5秒,处理一个文件需要2秒.处理两个文件则需要: 5秒读取文件A 2秒处理文件A 5秒读取文件B 2秒处理文件B --------------------- 总共需要14秒 从磁盘中读取文件的时候,大部分的CPU时间用于等待磁盘去读取数据.在这段时间里,CPU非常的

  • 浅谈Java多线程实现及同步互斥通讯

    Java多线程深入理解本文主要从三个方面了解和掌握多线程: 1. 多线程的实现方式,通过继承Thread类和通过实现Runnable接口的方式以及异同点. 2. 多线程的同步与互斥中synchronized的使用方法. 3. 多线程的通讯中的notify(),notifyAll(),及wait(),的使用方法,以及简单的生成者和消费者的代码实现. 下面来具体的讲解Java中的多线程: 一:多线程的实现方式 通过继承Threa类来实现多线程主要分为以下三步: 第一步:继承 Thread,实现Thr

  • 浅谈Java泛型让声明方法返回子类型的方法

    泛型典型的使用场景是集合.考虑到大多数情况下集合是同质的(同一类型),通过声明参数类型,可免去类型转换的麻烦.本文将讨论本人阅读Spring Security源码时遇到的一个关于泛型递归模式的问题. 声明方法返回子类型 在Spring Security的源码里有一个ProviderManagerBuilder接口,声明如下 public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> ext

随机推荐