zoukankan      html  css  js  c++  java
  • 04_线程的创建和启动_使用Callable和Future的方式

    【简述】

    从java5开始,java提供了Callable接口,这个接口可以是Runnable接口的增强版,

    Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能更强大。

    【call()方法特点】

    1.call()方法可以有返回值

    2.call()方法可以声明抛出异常。

    【Future接口】

    java5提供了Future接口来代表Callable接口里的call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口,所以这样可以作为Thread的target。

    在Future接口里定义了一下公共方法来控制它关联的Callable任务。

    1. boolean cancel( boolean mayInterruptRunning):试图取消该Future里关联的Callable任务。

    2. V get() :返回Callable任务里call()方法的返回值。调用该方法会导致程序阻塞,必须等到子线程结束后才会得到返回值。

    3. V get( long timeout, TimeUnit unit ):返回Callable任务里call方法的返回值。该方法然程序最多阻塞timeout和unit指定的时间,如果时间到了Callable没返回值,抛TimeoutException异常。

    4.boolean isCancelled():如果Callable任务正常完成前被取消,返回true。

    5.boolean isDone():如果Callable任务已完成,则返回true。

    【创建和启动线程的步骤】

    1.创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法没有返回值,再创建Callable实现类的实例。(从java8开始,可以直接使用Lambda表达式创建Callable对象)。

    2.使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

    3.使用FutureTask作为Thread对象的target创建并启动新线程。

    4.调用FutureTask对象的get方法来获得子线程执行结束后的返回值。

     【示例代码】

    package com.Higgin.part01;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    class ThirdThread {
        
    }
    
    public class Demo3 {
        
        public static void main(String[] args) {
            //创建Callable对象
            ThirdThread rt=new ThirdThread();
            //先使用Lambda表达式创建Callable<Integer>对象,
            //并使用FutureTask来包装Callable对象
            FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{
                int i=0;
                for(;i<1000;i++){
                    System.out.println(Thread.currentThread().getName()+"===="+i);
                }
                //call()方法可以有返回值
                return i;
            });
            
            
            
            for(int i=0;i<1000;i++){
                System.out.println(Thread.currentThread().getName()+"===="+i);
                if(i==20){
                    Thread t1=new Thread(task,"有返回值的线程");
                    t1.start();
                }
            }
            try {
                System.out.println("子线程的返回值:"+task.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    【运行结果】

    【总结】

    1.红框内的代码是以Callable对象来启动线程的关键代码。首先使用Lambda表达式创建一个Callable对象,然后将该线程包装成一个FutureTask对象。

    2.主线程中,当循环变量i=20时,程序启动以FutureTask对象为target的线程。程序最后调用FutureTask对象的get()方法来返回call()方法的返回值---该方法将导致主线程被阻塞,直到call()方法结束并返回为止。

    【采用实现Runnable、Callable接口方式创建多线程】

    【优点】
    1.线程只是实现了Runable接口或者Callable接口,还可以继承其它类。

    2.在这种方式下,多个线程可以共享同一个target对象,比较适合多个相同线程来处理同一份资源的情况。

    【缺点】

    编程略复杂,如果需要访问当前线程,则必须使用Thread currentThread()方法。

    【采用继承Thread类来创建多线程】

    【优点】

    编写简单,如果需要访问当前线程,只需使用this即可获得当前线程。

    【缺点】

    因为继承了Thread类,所以不能再继承其他父类。

    【分析】

    一般推荐采用实现Runnable、Callable接口的方式来创建多线程。

  • 相关阅读:
    2013第2周四晴
    2012第53周&2013第1周日
    2013周六雪转阴
    2013年第二周日生活整理
    php技术–php中感叹号!和双感叹号!!的用法(三元运算)
    laravel拓展validator验证
    laravel 5 自定义全局函数,怎么弄呢?
    Laravel 清空配置缓存
    网上很多laravel中cookie的使用方法。
    艾伟也谈项目管理,给敏捷团队中的架构师的10个建议 狼人:
  • 原文地址:https://www.cnblogs.com/HigginCui/p/5901713.html
Copyright © 2011-2022 走看看