La diferencia entre Runnable y Callable de oferta

Ejecutable

La interfaz Runnable es muy simple, define un método run(), que implementa el método run de la interfaz Runnable para realizar subprocesos múltiples.

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

Llamable

Mucha gente sabe que para obtener resultados de valor de retorno asíncronos en subprocesos múltiples, generalmente se logra mediante el uso de las interfaces Callable y FutureTask, pero es posible que muchas personas no sepan que Callable se basa en el método de ejecución de Runnable para realizar tareas, y luego pasa FutureTask para recopilar los resultados del valor de retorno, simulemos y escribamos un código FutureTask para ver cómo se implementa.


 /**
 * @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;
    }
}

Escribamos una demostración para probarlo

/**
 * @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
    }
}

Puede ver que nuestra demostración también se ejecuta normalmente, por lo que el punto clave es que Callable depende de Runnablecorrermétodo para realizar tareas

Supongo que te gusta

Origin blog.csdn.net/a1774381324/article/details/121578160
Recomendado
Clasificación