`
Everyday都不同
  • 浏览: 713464 次
  • 性别: Icon_minigender_1
  • 来自: 宇宙
社区版块
存档分类
最新评论

【转】线程返回值的方式介绍

阅读更多

原文地址:http://smalltalllong.iteye.com/blog/1156407

在Java5之前,线程是没有返回值的,常常为了“有”返回值,破费周折,而且代码很不好写。或者干脆绕过这道坎,走别的路了。
 
现在Java终于有可返回值的任务(也可以叫做线程)了。
 
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。
 
执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。
 
下面是个很简单的例子:
Java代码  
import java.util.concurrent.*;  
  
/** 
* Java线程:有返回值的线程 
* 
* @author Administrator  
*/  
public class Test {  
        public static void main(String[] args) throws ExecutionException, InterruptedException {  
                //创建一个线程池  
                ExecutorService pool = Executors.newFixedThreadPool(2);  
                //创建两个有返回值的任务  
                Callable c1 = new MyCallable("A");  
                Callable c2 = new MyCallable("B");  
                //执行任务并获取Future对象  
                Future f1 = pool.submit(c1);  
                Future f2 = pool.submit(c2);  
                //从Future对象上获取任务的返回值,并输出到控制台  
                System.out.println(">>>"+f1.get().toString());  
                System.out.println(">>>"+f2.get().toString());  
                //关闭线程池  
                pool.shutdown();  
        }  
}  
  
class MyCallable implements Callable{  
        private String oid;  
  
        MyCallable(String oid) {  
                this.oid = oid;  
        }  
  
        @Override  
        public Object call() throws Exception {  
                return oid+"任务返回的内容";  
        }  
}  
 输出结果:
>>>A任务返回的内容 
>>>B任务返回的内容 

Process finished with exit code 0

非常的简单,要深入了解还需要看Callable和Future接口的API啊。

第二种方法:
从线程中返回数据和向线程传递数据类似。也可以通过类成员以及回调函数来返回数据。但类成员在返回数据和传递数据时有一些区别,下面让我们来看看它们区别在哪。
  一、通过类变量和方法返回数据
  使用这种方法返回数据需要在调用start方法后才能通过类变量或方法得到数据。让我们先来看看会得到什么结果。
Java代码  
package mythread;  
  
public class MyThread extends Thread  
{  
    private String value1;  
    private String value2;  
  
    public void run()  
    {  
        value1 = "通过成员变量返回数据";  
        value2 = "通过成员方法返回数据";  
    }  
    public static void main(String[] args) throws Exception  
    {  
        MyThread thread = new MyThread();  
        thread.start();  
        System.out.println("value1:" + thread.value1);  
        System.out.println("value2:" + thread.value2);  
    }  
}  
 运行上面的代码有可能输出如下的结果:
  value1:null
  value2:null
  从上 面的运行结果看很不正常。在run方法中已经对value1和value2赋了值,而返回的却是null。发生这种情况的原因是调用start方法后就立 刻输出了value1和value2的值,而这里run方法还没有执行到为value1和value2赋值的语句。要避免这种情况的发生,就需要等run 方法执行完后才执行输出value1和value2的代码。因此,我们可以想到使用sleep方法将主线程进行延迟,如可以在 thread.start()后加一行如下的语句:sleep(1000);
  这样做可以使主线程延迟1秒后再往下执行,但这样做有一个问题,就是我们怎么知道要延迟多长时间。在这 个例子的run方法中只有两条赋值语句,而且只创建了一个线程,因此,延迟1秒已经足够,但如果run方法中的语句很复杂,这个时间就很难预测,因此,这 种方法并不稳定。
  我们的目的就是得到value1和value2的值,因此,只要判断value1和value2是否为null。如果它们都不为null时,就可以输出这两个值了。我们可以使用如下的代码来达到这个目的:
  while (thread.value1 == null || thread.value2 == null);
   使用上面的语句可以很稳定地避免这种情况发生,但这种方法太耗费系统资源。大家可以设想,如果run方法中的代码很复杂,value1和value2需 要很长时间才能被赋值,这样while循环就必须一直执行下去,直到value1和value2都不为空为止。因此,我们可以对上面的语句做如下的改进:
  while (thread.value1 == null || thread.value2 == null)
   sleep(100);
  在while循环中第判断一次value1和value2的值后休眠100毫秒,然后再判断这两个值。这样所占用的系统资源会小一些。
   上面的方法虽然可以很好地解决,但Java的线程模型为我们提供了更好的解决方案,这就是join方法。在前面已经讨论过,join的功能就是使用线程 从异步执行变成同步执行。当线程变成同步执行后,就和从普通的方法中得到返回数据没有什么区别了。因此,可以使用如下的代码更有效地解决这个问题:
Java代码  
...  
thread.start();  
thread.join();  
...  
 在thread.join()执行完后,线程thread的run方法已经退出了,也就是说线程thread已经结束了。因此,在thread.join()后面可以放心大胆地使用MyThread类的任何资源来得到返回数据。 

第三种:
通过回调函数返回数据
  下面例子中通过Work类的process方法向线程中传递了计算结果,但同时,也通过process方法从线程中得到了三个随机数。因此,这种方法既可以向线程中传递数据,也可以从线程中获得数据。
Java代码  
package mythread;  
  
class Data  
{  
    public int value = 0;  
}  
class Work  
{  
    public void process(Data data, Integer numbers)  
    {  
        for (int n : numbers)  
        {  
            data.value += n;  
        }  
    }  
}  
public class MyThread3 extends Thread  
{  
    private Work work;  
  
    public MyThread3(Work work)  
    {  
        this.work = work;  
    }  
    public void run()  
    {  
        java.util.Random random = new java.util.Random();  
        Data data = new Data();  
        int n1 = random.nextInt(1000);  
        int n2 = random.nextInt(2000);  
        int n3 = random.nextInt(3000);  
        work.process(data, n1, n2, n3);   // 使用回调函数  
        System.out.println(String.valueOf(n1) + "+" + String.valueOf(n2) + "+"  
                + String.valueOf(n3) + "=" + data.value);  
    }  
    public static void main(String[] args)  
    {  
        Thread thread = new MyThread3(new Work());  
        thread.start();  
    }  
}  
 在上面代码 中的 process方法被称为回调函数。从本质上说,回调函数就是事件函数。在 Windows API中常使用回调函数和调用 API的程序之间进行数据交互。因此,调用回调函数的过程就是最原始的引发事件的过程。在这个例子中调用了 process方法来获得数据也就相当于在 run方法中引发了一个事件

 

分享到:
评论

相关推荐

    python使用threading获取线程函数返回值的实现方法

    主要介绍了python使用threading获取线程函数返回值的实现方法,需要的朋友可以参考下

    易语言线程返回数据的方法

    易语言线程返回数据的方法源码,线程返回数据的方法,线程

    vc中获取一个线程的状态及返回值

    vc中获取一个线程的状态及返回值,VS2012工程,通过点击界面上按钮,启动一个判断线程,然后再这个判断线程启动一个工作线程,在判断线程里判断工作线程的工作状态

    在Java 线程中返回值的用法

    NULL 博文链接:https://icgemu.iteye.com/blog/467848

    Future执行具有返回值的线程.txt

    大家都知道实现多线程的2种方式,今天来讲讲Future实现具有返回值的线程。应用场景:前端调用时无需等待线程结束返回,线程结束后需进行其它操作如更新状态、通知kafuka等。

    C++11获取线程返回值的实现代码

    假设我们的app会创建一个线程来压缩一个文件夹,该线程在压缩完文件夹后会返回压缩文件 *.zip 和这个zip文件的大小,我们现在就想获得这个线程的返回值。 有两种方法可以实现这个需求: 1. 传统的方法:在线程间共享...

    C++多线程获取返回值方法详解

    主要介绍了C++多线程获取返回值方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    python获取多线程及子线程的返回值

    最近有个需求,用多线程比较合适,但是我需要每个线程的返回值,这就需要我在threading.Thread的基础上进行封装 import threading class MyThread(threading.Thread): def __init__(self,func,args=()): super...

    Python多线程获取返回值代码实例

    这篇文章主要介绍了Python多线程获取返回值代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在使用多线程的时候难免想要获取其操作完的返回值进行其他...

    使用Runnable模拟Callable接口实现线程有返回值

    大家都知道Runnable和Callable接口都可以作为其他线程执行的任务,但是Runnable接口的run方法没有返回值,而Callable接口的call方法有返回值,那么Callable接口是如何做到的呢?在此我给出一个Demo,看看通过...

    有返回值的线程

    NULL 博文链接:https://ericlntm.iteye.com/blog/742942

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

    主要介绍了多线程返回值使用示例(callable与futuretask),需要的朋友可以参考下

    Linux多线程编程-线程函数返回值(返回复杂数据类型)

    通过几个实验练习,学习线程之间连接的具体实现。下面列举了两个例子,一个是子线程返回简单数据类型;另一个是子线程返回复杂数据类型。 实现代码 子线程返回复杂数据类型 #include #include #include #include ...

    可用于VC++的多线程编程

    可用于VC++的多线程编程,可用于VC++的多线程编程

    python利用多进程、多线程实现网络数据下载(百度地图api中规划路径数据)

    使用python的多进程、多线程技术,实现互联网数据的并行下载,一个进程可以设置n个线程,多进程通过开启多个运行脚本来实现,这样可以根据具体的硬件环境任意启动多个进程。数据主要是通过下载百度地图api中

    java多线程编程总结

    Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征...

    Java多线程编程总结

    Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上) Java线程:新特征-锁(下) Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程...

Global site tag (gtag.js) - Google Analytics