Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在java中运行异步作业时实现优雅取消的最佳方法_Java_Java.util.concurrent - Fatal编程技术网

在java中运行异步作业时实现优雅取消的最佳方法

在java中运行异步作业时实现优雅取消的最佳方法,java,java.util.concurrent,Java,Java.util.concurrent,假设我有一个这样的接口,可以让应用程序中的组件运行作业- IJob { IResult execute(); void cancel(); } 我想设置我的应用程序,以便异步运行这些作业。我们期望调用cancel会立即返回execute,结果表明它已被取消 最好的设置方法是什么?我可以创建一个Thread对象来运行它,它有额外的方法可以取消,但我也在研究我新接触的未来接口 FutureTask的问题是取消不合适,不允许我调用job.cancel()。扩展FutureTask并实

假设我有一个这样的接口,可以让应用程序中的组件运行作业-

IJob {
    IResult execute();
    void cancel();
}
我想设置我的应用程序,以便异步运行这些作业。我们期望调用cancel会立即返回execute,结果表明它已被取消

最好的设置方法是什么?我可以创建一个Thread对象来运行它,它有额外的方法可以取消,但我也在研究我新接触的未来接口


FutureTask的问题是取消不合适,不允许我调用job.cancel()。扩展FutureTask并实现我自己对它的处理是一个好主意吗?

当您在任务中调用
cancel
时,它会向运行任务的线程发送一个中断信号。您的任务需要定期检查该信号是否已发送,并在出现以下情况时做出相应反应:

if (Thread.interrupted()) {
    performNecessaryCleanup();
    return;
}

在任务中调用
cancel
时,它将向运行任务的线程发送一个中断信号。您的任务需要定期检查该信号是否已发送,并在出现以下情况时做出相应反应:

if (Thread.interrupted()) {
    performNecessaryCleanup();
    return;
}

在使用并发时,使用语言提供的内容,而不是手工实现

据我所知,应该是适合您的工具,因为您可以:

  • 提供将异步运行并可能返回结果的it作业
  • 关闭执行器,以便取消所有正在运行的作业
范例

public static void main(String[] args) {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    List<Future<IResult>> results = new ArrayList<>();

    for (int i = 0; i < 10; i++) {
        results.add(executor.submit(new Job(i))); //start jobs
    }

    executor.shutdownNow(); //attempts to stop all running jobs

    //program flow immediatly continues
}

在使用并发时,使用语言提供的内容,而不是手工实现

据我所知,应该是适合您的工具,因为您可以:

  • 提供将异步运行并可能返回结果的it作业
  • 关闭执行器,以便取消所有正在运行的作业
范例

public static void main(String[] args) {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    List<Future<IResult>> results = new ArrayList<>();

    for (int i = 0; i < 10; i++) {
        results.add(executor.submit(new Job(i))); //start jobs
    }

    executor.shutdownNow(); //attempts to stop all running jobs

    //program flow immediatly continues
}

调用IJob.execute()FutureTask.run()将阻止当前线程,您需要调用IJobFutureTask

安排FutureTask是最好的选择,消费者可以调用FutureTask.get()并等待结果(即使您调用IJob.cancel()

我对IJob和IResult进行了一些演示,它使用普通线程进行调度,在生产中,您应该像前面的帖子示例一样拥有一个执行服务

如您所见,主线程可以检查状态调用FutureTask.isDone(),基本上是检查结果是否已设置。设置结果意味着IJob的线程已完成

如果方法与您的评论中的行为相同,您几乎可以在任何时候调用IJob.cancel()来完成FutureTask中包装的IJob

模拟作业:

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true
模拟结果:

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true
主类:

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true
输出(线程睡眠(15000)):

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true

调用IJob.execute()FutureTask.run()将阻止当前线程,您需要调用IJobFutureTask

安排FutureTask是最好的选择,消费者可以调用FutureTask.get()并等待结果(即使您调用IJob.cancel()

我对IJob和IResult进行了一些演示,它使用普通线程进行调度,在生产中,您应该像前面的帖子示例一样拥有一个执行服务

如您所见,主线程可以检查状态调用FutureTask.isDone(),基本上是检查结果是否已设置。设置结果意味着IJob的线程已完成

如果方法与您的评论中的行为相同,您几乎可以在任何时候调用IJob.cancel()来完成FutureTask中包装的IJob

模拟作业:

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true
模拟结果:

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true
主类:

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true
输出(线程睡眠(15000)):

public class MockJob implements IJob {

    private boolean cancelled;

    public MockJob() {
    }

    @Override
    public IResult execute() {
        int count = 0;
        while (!cancelled) {
            try {
                count++;
                System.out.println("Mock Job Thread: count = " + count);
                if (count >= 10) {
                    break;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                cancelled = true;
            }
        }
        return new MockResult(cancelled, count);
    }

    @Override
    public void cancel() {
        cancelled = true;
    }
}
public class MockResult implements IResult {

    private boolean cancelled;
    private int result;

    public MockResult(boolean cancelled, int result) {
        this.cancelled = cancelled;
        this.result = result;
    }

    public boolean isCancelled() {
        return cancelled;
    }

    public int getResult() {
        return result;
    }
}
public class Main {

    public static void main(String[] args) throws InterruptedException {
        // Job
        IJob mockJob = new MockJob();

        // Async task
        FutureTask<IResult> asyncTask = new FutureTask<>(mockJob::execute);
        Thread mockJobThread = new Thread(asyncTask);

        // Show result
        Thread showResultThread = new Thread(() -> {
            try {
                IResult result = asyncTask.get();
                MockResult mockResult = (MockResult) result;
                Thread thread = Thread.currentThread();
                System.out.println(String.format("%s: isCancelled = %s, result = %d",
                        thread.getName(),
                        mockResult.isCancelled(),
                        mockResult.getResult()
                ));
            } catch (InterruptedException | ExecutionException ex) {
                // NO-OP
            }
        });

        // Check status
        Thread monitorThread = new Thread(() -> {
            try {
                while (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: asyncTask.isDone = %s",
                            thread.getName(),
                            asyncTask.isDone()
                    ));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
            Thread thread = Thread.currentThread();
            System.out.println(String.format("%s: asyncTask.isDone = %s",
                    thread.getName(),
                    asyncTask.isDone()
            ));
        });

        // Async cancel
        Thread cancelThread = new Thread(() -> {
            try {
                // Play with this Thread.sleep, set to 15000
                Thread.sleep(5000);
                if (!asyncTask.isDone()) {
                    Thread thread = Thread.currentThread();
                    System.out.println(String.format("%s: job.cancel()",
                            thread.getName()
                    ));
                    mockJob.cancel();
                }
            } catch (InterruptedException ex) {
                // NO-OP
            }
        });

        monitorThread.start();
        showResultThread.start();
        cancelThread.setDaemon(true);
        cancelThread.start();
        mockJobThread.start();
    }
}
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-3: job.cancel()
Thread-2: asyncTask.isDone = false
Thread-1: isCancelled = true, result = 5
Thread-2: asyncTask.isDone = true
Thread-2: asyncTask.isDone = false
Thread-0: count = 1
Thread-2: asyncTask.isDone = false
Thread-0: count = 2
Thread-2: asyncTask.isDone = false
Thread-0: count = 3
Thread-2: asyncTask.isDone = false
Thread-0: count = 4
Thread-2: asyncTask.isDone = false
Thread-0: count = 5
Thread-2: asyncTask.isDone = false
Thread-0: count = 6
Thread-2: asyncTask.isDone = false
Thread-0: count = 7
Thread-2: asyncTask.isDone = false
Thread-0: count = 8
Thread-2: asyncTask.isDone = false
Thread-0: count = 9
Thread-2: asyncTask.isDone = false
Thread-0: count = 10
Thread-1: isCancelled = false, result = 10
Thread-2: asyncTask.isDone = true

未来的“不优雅”是怎么回事?多线程是很难的,试图改变未来的实现很可能会引入bug。确定“不优雅”可能不是最好的选择。我的意思是cancel()发送了一个线程中断,但实际上并没有给我时间来正确调用job.cancel()。如果我创建了一个调用job.execute()的FutureTask(阻塞调用),那么我将如何处理取消请求以便调用job.cancel()?什么?对不起,我一点也不明白。您必须向我们展示一些代码,解释为什么您没有时间做某事。(为了响应您的编辑:have
execute()
throw
InterruptedException
。但是Java
executerservice
是一个更好的主意。)同时启动一个新线程只是为了阻止它的完成也是一个糟糕的主意。您还可以让原始线程自己完成任务,如果您所做的只是阻塞和等待,那么将一无所获。您已停止一个线程,并在其位置启动另一个线程。重点是什么?我会尝试添加更多上下文。。。我工作的环境是一个插件架构,插件提供IJob实现。我不想让插件知道任何关于线程或处理中断异常等的知识。它们只是实现执行和取消。Future“不优雅”是怎么回事?多线程很难,试图更改Future的实现很可能会引入bug。Ok“不优雅”可能不是最好的选择。我的意思是cancel()发送了一个线程中断,但实际上并没有给我时间来正确调用job.cancel()。如果我创建一个未来任务调用