• java 线程相关(3)


    1、 Future定义

    Future是java1.5版本引进的一个接口,可以用来获取异步执行的结果,提供了一些查看异步任务状态的方法。

    FutureTask是Future接口的一个实现类,常用来配合Callable任务,实现异步执行并能获取到任务的执行结果。

    PS: 注意future接口获取异步任务返回的get方法是一个阻塞方法,要对其合理的使用。

    • FutureTask关系图

    • Future定义的一些方法

    1、boolean cancel(boolean mayInterruptIfRunning)
    尝试取消当前任务的执行。如果任务已经取消、已经完成或者其他原因不能取消,尝试将失败。如果任务还没有启动就调用了cancel(true),任务将永远不会被执行。如果任务已经启动,参数mayInterruptIfRunning将决定任务是否应该中断执行该任务的线程,以尝试中断该任务。
    如果任务不能被取消,通常是因为它已经正常完成,此时返回false,否则返回true

    2、boolean isCancelled()
    查询任务是否取消成功

    3、boolean isDone()
    查询任务是否已经完成

    4、V get() 阻塞方法
    等待任务结束,然后获取结果,如果任务在等待过程中被终端将抛出InterruptedException,如果任务被取消将抛出CancellationException,如果任务中执行过程中发生异常将抛出ExecutionException。

    5、V get(long timeout, TimeUnit unit)
    任务最多在给定时间内完成并返回结果,如果没有在给定时间内完成任务将抛出TimeoutException。

    • Future的简单例子
        public static void main(String[] args) throws ExecutionException, InterruptedException {
    
            Long startTime = System.currentTimeMillis();
    
            FutureTask<String> futureTask1 = new FutureTask<>(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Thread.sleep(5000);
                    return "future1";
                }
            });
    
            new Thread(futureTask1).start();
    
            FutureTask<String> futureTask2 = new FutureTask<>(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Thread.sleep(3000);
                    return "future2";
                }
            });
    
            new Thread(futureTask2).start();
    
            //等待future1和future2执行完 ,get()阻塞
            System.out.println(futureTask1.get() + "执行完!");
            System.out.println(futureTask2.get() + "执行完!");
    
            Long endTime = System.currentTimeMillis();
    
            // 5004 可以看出future1和future2是异步执行的
            System.out.println("共用时: " + (endTime - startTime));
    
        }
    

    2、FutureTask的源码解析

    从上述例子,我们可以看到,FutureTask任务执行的调用是 new Thread(futureTask).start()这样的,即线程将FutureTask当成一个Runnable任务体执行。

    注:FutureTask本身就实现了RunnalbeFuture接口(即Runnable接口和Future接口)

    可以着重看下FutureTask中的run()方法

        public void run() {
            // java不能直接访问操作系统底层,而是通过本地方法来访问,Unsafe类提供了硬件级别的原子操作。
            // UNSAFE.compareAndSwapObject在obj的offset位置比较object field和期望的值,如果相同则更新。field值修改会返回true
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return;
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran; // 判断任务是否执行成功
                    try {
                        result = c.call(); // 这里保存了Callable任务的返回值
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        setException(ex); // 设置异常
                    }
                    if (ran)
                        set(result); // 设置任务执行结果
                }
            } finally {
                runner = null;
                int s = state;
                if (s >= INTERRUPTING)
                    handlePossibleCancellationInterrupt(s);
            }
        }
    

    set(result)方法:

        protected void set(V v) {
            if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
                outcome = v; //保存任务的返回结果,FutureTask的内部属性outcome
                UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
                finishCompletion();
            }
        }
    

    可以看出,FutureTask只是将自己的run方法中实现对Callabe任务的执行和保存结果。

    获取任务的返回值 FutureTask.get()方法

        public V get() throws InterruptedException, ExecutionException {
            int s = state;
            if (s <= COMPLETING)
                // 等待任务完成,并且移除waiters这个等待线程的节点
                s = awaitDone(false, 0L);
            return report(s); // 对返回值的封装,s其实是当前FutureTask的状态
        }
    

    可以看出FutureTask.get()是一个阻塞方法,在FutureTask中,state(当前任务运行状态)是用来判断任务是否完成的关键,

    3、扩展

    3.1、其实在set(result)方法中,UNSAFE方法操作state的地址状态为COMPLETING -> NORMAL,state也是FutureTask中其他方法判断是否执行的一个关键属性。

    state的几种流转情况:
    NEW -> COMPLETING -> NORMAL 正常情况
    NEW -> COMPLETING -> EXCEPTIONAL 异常情况
    NEW -> CANCELLED 被取消
    NEW -> INTERRUPTING -> INTERRUPTED 被打断

    3.2、在线程的相关工具中,state状态都是十分重要的属性,不同的状态会使相应的工具类呈现不同的任务执行。

    关于学习到的一些记录与知识总结
  • 相关阅读:
    浅出Java Socket 编程
    WPF指南之一(WPF的结构)
    使用URL访问网络资源
    WPF指南之三(XAML的名字空间)
    多线程并发思考文件加锁
    关于kindeditor上传图片出现"服务器发生故障"的解决办法
    isset function of PHP
    JSON字符串传到后台PHP处理的问题
    isset function of PHP
    (转)Linux利器 strace
  • 原文地址:https://www.cnblogs.com/Zxq-zn/p/14788469.html
Copyright © 2020-2023  润新知