关于java:面试题之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办法进行执行工作的

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理