面试官:我现在想要主线程中断线程池中的任务,我可以怎么做
我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方法。
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 那这时候,我们可以在对应的实现代码写出对应的处理。
结果
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; // 退出任务循环
}
}
}
}