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

1、概述异步

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

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

2、实现this

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

复制代码
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表示的是该任务执行以后返回结果的类型。.net

  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方法要返回的参数类型。code

  3.Future类型对象

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

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

 

 

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

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

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

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


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

先看以下一段代码

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);
}

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

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

3、实现 Callable 接口

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

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

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

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

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

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;
}


}

}

相关文章
相关标签/搜索