面试题之Runnable和Callable的区别

Posted 隐 风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试题之Runnable和Callable的区别相关的知识,希望对你有一定的参考价值。

Runnable

Runnable接口非常简单,就定义了一个方法run(), 实现Runnable接口的run方法就可以实现多线程

// 函数式接口
@FunctionalInterface
public interface Runnable 
    public abstract void run();


Callable

很多人都知道要想在多线程中获取异步返回值结果一般是用Callable和FutureTask接口来配合实现,但可能很多人都不知道其实Callable是依赖于Runnable的run方法进行执行任务的,然后在通过FutureTask来收集返回值结果,下面咱们就自己模拟写一份FutureTask代码来看看是怎么实现的吧。


 /**
 * @author yinfeng
 * @description  自己实现futureTask,基于park/unpark进行线程通讯
 * @since 2022/1/9 21:32
 */
public class MyFutureTask<T> implements Runnable 
     Callable<T> callable;
    /**
     * callable执行结果
     */
    T result;
    /**
     * task执行状态
     */
    String state = "new";
    /**
     * 存储正在等待的消费者
     */
    LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();

    public MyFutureTask(Callable<T> callable) 
        this.callable = callable;
    

    @Override
    public void run() 
        try 
            result = callable.call();
         catch (Exception e) 
            e.printStackTrace();
         finally 
            state = "end";
        

        // 任务执行完成后通过unpark通知消费者
        System.out.println(Thread.currentThread().getName() + " 生产者执行结束,通知消费者");
        while (true) 
            Thread waiter = waiters.poll();
            if (waiter == null) 
                break;
            
            LockSupport.unpark(waiter);
        
    

    /**
     * park / unpark
     */
    public T get() throws Exception 
        Thread mainThread = Thread.currentThread();
        // 塞入等待的集合中
        waiters.add(mainThread); 
        // 判断状态
        System.out.println(Thread.currentThread().getName() + " 消费者进入等待");
        while (!"end".equals(state)) 
        	// 阻塞等待任务执行完成后通知
            LockSupport.park(mainThread);
        
        return result;
    

我们写个demo测试一下

/**
 * @author yinfeng
 * @description
 * @since 2022/1/9 21:32
 */
public class FutureTaskTest 
    public static void main(String[] args) throws Exception 
        final MyFutureTask<String> futureTask = new MyFutureTask<>(() -> 
            Thread.sleep(5000);
            return "任务完成888";
        );
        new Thread(futureTask).start();
        final String result = futureTask.get();
        System.out.println("结果:"+result);
        // 控制台打印如下: 
        // main 消费者进入等待
		// Thread-0 生产者执行结束,通知消费者
		// 结果:任务完成888
    

可以看到我们的demo也是正常运行的,所以很关键的一点还是Callable是依赖于Runnable的run方法进行执行任务的

以上是关于面试题之Runnable和Callable的区别的主要内容,如果未能解决你的问题,请参考以下文章

java中Runnable和Callable的区别

Callable 和 Runnable 的区别

Java中Runnable和Thread以及Callable的区别

Callable和Runnable接口的区别

callable和runnable的区别

callable和runnable的区别