• Runable和Callable接口


    Runable和Callable两者联系:

      两者都是多线程开发需要实现的接口,Callable不能直接替换Runable,需要通过Runable接口的实现类FutherTask包装一下,才可以在Thread中使用,底层还是通过Runable接口的run方法调用Callable中的call方法处理业务逻辑。

    Runable和Callable两者区别:

      Runable接口是JDK1.0引入的,没有返回值,也无法抛出异常。

      Callable接口有返回值,可以抛出异常。

    异步运算考虑使用Callable接口

    多线程应用有两种实现方式,一种是实现Runnable接口,另一种是继承Thread类,这两个方法都有缺点:run方法没有返回值,不能抛出异常(这两个缺点归根到底是Runnable接口的缺陷,Thread类也实现了Runnable接口),如果需要知道一个线程的运行结果就需要用户自行设计,线程类本身也不能提供返回值和异常。但是从Java1.5开始引入了一个新的接口Callable,它类似于Runnable接口,实现它就可以实现多线程任务,Callable的接口定义如下:

    public interface Callable<V> {
        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        V call() throws Exception;
    }

    实现Callable接口的类,只是表明它是一个可调用的任务,并不表示它具有多线程运算能力,还是需要执行器来执行的,我们先编写一个任务类,代码如下: 

    //税款计算器
    class TaxCalculator implements Callable<Integer> {
        // 本金
        private int seedMoney;
    
        // 接收主线程提供的参数
        public TaxCalculator(int _seedMoney) {
            seedMoney = _seedMoney;
        }
    
        @Override
        public Integer call() throws Exception {
            // 复杂计算,运行一次需要2秒
            TimeUnit.MILLISECONDS.sleep(2000);
            return seedMoney / 10;
        }
    }

    这里模拟了一个复杂运算:税款计算器,该运算可能要花费10秒钟的时间,此时不能让用户一直等着吧,需要给用户输出点什么,让用户知道系统还在运行,这也是系统友好性的体现:用户输入即有输出,若耗时较长,则显示运算进度。如果我们直接计算,就只有一个main线程,是不可能有友好提示的,如果税金不计算完毕,也不会执行后续动作,所以此时最好的办法就是重启一个线程来运算,让main线程做进度提示,代码如下:

    public static void main(String[] args) throws InterruptedException,
                ExecutionException {
            // 生成一个单线程的异步执行器
            ExecutorService es = Executors.newSingleThreadExecutor();
            // 线程执行后的期望值
            Future<Integer> future = es.submit(new TaxCalculator(100));
            while (!future.isDone()) {
                // 还没有运算完成,等待200毫秒
                TimeUnit.MICROSECONDS.sleep(200);
                // 输出进度符号
                System.out.print("*");
            }
            System.out.println("
    计算完成,税金是:" + future.get() + "  元 ");
            es.shutdown();
        }

    在这段代码中,Executors是一个静态工具类,提供了异步执行器的创建能力,如单线程异步执行器newSingleThreadExecutor、固定线程数量的执行器newFixedThreadPool等,一般它是异步计算的入口类。future关注的是线程执行后的结果,比如没有运行完毕,执行结果是多少等。此段代码的运行结果如下所示:

          **********************************************......

          计算完成,税金是:10  元

      执行时,"*"会依次递增,表示系统正在运算,为用户提供了运算进度,此类异步计算的好处是:

    • 尽可能多的占用系统资源,提供快速运算
    • 可以监控线程的执行情况,比如是否执行完毕、是否有返回值、是否有异常等。
    • 可以为用户提供更好的支持,比如例子中的运算进度等。
  • 相关阅读:
    Node.js缓冲模块Buffer
    hashMap底层put和get方法逻辑
    减少GC开销的措施
    mybatis中#{}和${}的区别
    AngularJS 用 Interceptors 来统一处理 HTTP 请求和响应
    点击页面的悬浮窗口实现随意拖动
    RabbitMQ 基本概念介绍-----转载
    Spring+Quartz实现定时执行任务的配置
    springmvc导出excel并弹出下载框
    AtomicInteger类保证线程安全的用法
  • 原文地址:https://www.cnblogs.com/jvStarBlog/p/11796329.html
Copyright © 2020-2023  润新知