FutureTask

80 阅读2分钟

面试官:我现在想要主线程中断线程池中的任务,我可以怎么做

我os:中断就用interrupt,但是主线程怎么对线程池内的线程下手呢,想不懂

我回答:用公共变量,要中断就主线程设置一下,线程池内发现变量值为true,就自行中断

面试官: 门口在那边~

其实,FutureTask 就能解决这个问题

---- 以下代码基于jdk11

FutureTask

二话不说,先来个demo看看FutureTask是什么。

public class Demo {  
  
    public static void main(String[] args){
	    Callable<Integer> callable = new Callable<Integer>() {  
	    @Override  
	    public Integer call() throws Exception {  
	        // 执行任务  
	        return 42;  
	    }  };  
  
		FutureTask<Integer> futureTask = new FutureTask<>(callable);  
		  
		Thread thread = new Thread(futureTask);  
		thread.start();  
		  
		// 阻塞当前线程等待任务结果  
		Integer result = futureTask.get();  
		System.out.println("结果: " + result);
	}    
}

众所周知,thread的入参是runnable,那怎么将callable设置进去的,当然是适配器模式啦。 适配器就是我们的FutureTask。

public interface RunnableFuture<V> extends Runnable, Future<V> {  
      void run();  
}

public class FutureTask<V> implements RunnableFuture<V> {
	private Callable<V> callable;  
	/** The result to return or exception to throw from get() */  
	private Object outcome; // non-volatile, protected by state reads/writes  
	/** The thread running the callable; CASed during run() */  
	private volatile Thread runner;  
	/** Treiber stack of waiting threads */  
	private volatile WaitNode waiters;


	// 实现run方法
	public void run() {  
	    if (state != NEW ||  
	        !RUNNER.compareAndSet(this, null, Thread.currentThread()))  
	        return;  
	    try {  
	        Callable<V> c = callable;  
	        if (c != null && state == NEW) {  
	            V result;  
	            boolean ran;  
	            try {  
			        // 这里不就是最终调用了call的实现方法,所以我们才拿到了结果。
	                result = c.call();  
	                ran = true;  
	            } catch (Throwable ex) {  
	                result = null;  
	                ran = false;  
	                setException(ex);  
	            }  
	            if (ran)  
	                set(result);  
	        }  
	    } finally {  
	        // runner must be non-null until state is settled to  
	        // prevent concurrent calls to run()        runner = null;  
	        // state must be re-read after nulling runner to prevent  
	        // leaked interrupts        int s = state;  
	        if (s >= INTERRUPTING)  
	            handlePossibleCancellationInterrupt(s);  
	    }  
	}

}

runner属性

FutureTask 的 runner属性,执行run方法的时候,通过cas set进去的。 这里就衍生出,cancel方法。

image.png

cancel

public class FutureTask<V> implements RunnableFuture<V> {
	public boolean cancel(boolean mayInterruptIfRunning) {  
	    if (!(state == NEW && STATE.compareAndSet  
	          (this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))  
	        return false;  
	    try {    // in case call to interrupt throws exception  
	        if (mayInterruptIfRunning) {  
	            try {  
	                Thread t = runner;  
	                if (t != null)  
		                // 标记中断
	                    t.interrupt();  
	            } finally { // final state  
	                STATE.setRelease(this, INTERRUPTED);  
	            }  
	        }  
	    } finally {  
	        finishCompletion();  
	    }  
	    return true;  
	}
}

可以看出,这个方法就是将线程,标记中断,也是因为futureTask的一个属性是thread,这就能直接操作了0.0 那这时候,我们可以在对应的实现代码写出对应的处理。

image.png

结果

futureTask除了callable,还能使用runnable。

这不就!能用了吗!

public class Demo {  
 
    public static void main(String[] args) {  
        // 创建一个线程池  
        ThreadPoolExecutor executor = new ThreadPoolExecutor(  
                5, 5, 0, TimeUnit.SECONDS,  
                new LinkedBlockingQueue<>()  
        );  
        // 提交任务给线程池  
        List<Future<?>> futures = new ArrayList<>();  
        for (int i = 0; i < 10; i++) {  
            Future<?> future = executor.submit(new MyRunnable(i));  
            futures.add(future);  
        }  
  
        try {  
            // 休眠1秒钟,让线程池中的任务有机会执行一段时间  
            Thread.sleep(1000);  
  
            // 中断并丢弃线程池中的任务  
            for (Future<?> future : futures) {  
                future.cancel(true);  
            }  
            futures.clear();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        } finally {  
            // 关闭线程池  
            executor.shutdown();  
        }  
    }  
}  
  
class MyRunnable implements Runnable {  
    private int id;  
  
    public MyRunnable(int id) {  
        this.id = id;  
    }  
  
    @Override  
    public void run() {  
        while (!Thread.currentThread().isInterrupted()) {  
            try {  
                // 模拟任务执行一些操作  
                System.out.println("Task " + id + " is running.");  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                // 捕捉中断异常并处理  
                System.out.println("Task " + id + " is interrupted.");  
                Thread.currentThread().interrupt(); // 重新设置中断状态  
                break; // 退出任务循环  
            }  
        }  
    }  
}