判断Java 的 Future 为啥还没结果

在诊断Java应用的时候, 我们经常看到很多异步的调用, 当前线程等待其它线程返回结果. 有时候会发现这些线程迟迟没有往下走, 于是查看线程状态, 会看到如下的线程栈:

sun.misc.Unsafe.park(Native Method) 
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) 
java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429) 
java.util.concurrent.FutureTask.get(FutureTask.java:191) 
com.tianxiaohui.RboCache.compute(RboCache.java:46)

我们会很自然的发问, 为什么它停在这, 到底发生了什么?

初步分析

对于这种情况, 有2种情况:

  1. 这个任务还没有被执行, 所以没有结果;
  2. 这个任务在执行中, 所以还没有结果;

对于第一种情况, 要去查看线程为什么没启动, 或者线程池为啥没执行它. 通常这时候要查看线程池的core size, max size, 和workQueue 和 workers 的情况.
对于第二种情况, 则要查看执行的线程在干什么事情, 为什么还没出结果.

java.util.concurrent.Future

对于java.util.concurrent.Future 我们很容易的能从它的字段: runner 看出谁在执行, 还是没有在执行, 如下图:
future1.png
future2.png

java.util.concurrent.CompletableFuture

对于 java.util.concurrent.CompletableFuture 则稍微麻烦一些, 要看谁指向它:

  1. 如果指向它的对象除了当前线程还有另外一个线程, 那么另外一个线程就是执行线程;
  2. 如果指向它的对象除了当前线程还有一个等待队列中的某个对象, 则它还没开始执行;
    cf1.png
    cf2.png

上面用到的代码:

import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Supplier;

public class WhyFutureStuck {
    
    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        
        Future<String> f1 = es.submit((Callable<String>) new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3600 * 1000);
                return "result-f1";
            }
        });
        
        CompletableFuture<String> cf1 = CompletableFuture.supplyAsync((Supplier<String>) () -> {
            try {
                Thread.sleep(3600 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "result-cf1";
        }, es);
        
        //threads are used up
        Future<String> f2 = es.submit((Callable<String>) new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3600 * 1000);
                return "result-f2";
            }
        });
        
        CompletableFuture<String> cf2 = CompletableFuture.supplyAsync((Supplier<String>) () -> {
            try {
                Thread.sleep(3600 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "result-cf2";
        }, es);
        
        try {
            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(cf1.get());
            System.out.println(cf2.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

标签: none

添加新评论