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方法進行執行任務的

到此這篇關於java面試常問的Runnable和Callable的區別的文章就介紹到這瞭,更多相關java Runnable和Callable區別內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: