在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()将阻止当前线程,您需要调用IJob或FutureTask 安排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()将阻止当前线程,您需要调用IJob或FutureTask 安排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()
throwInterruptedException
。但是Javaexecuterservice
是一个更好的主意。)同时启动一个新线程只是为了阻止它的完成也是一个糟糕的主意。您还可以让原始线程自己完成任务,如果您所做的只是阻塞和等待,那么将一无所获。您已停止一个线程,并在其位置启动另一个线程。重点是什么?我会尝试添加更多上下文。。。我工作的环境是一个插件架构,插件提供IJob实现。我不想让插件知道任何关于线程或处理中断异常等的知识。它们只是实现执行和取消。Future“不优雅”是怎么回事?多线程很难,试图更改Future的实现很可能会引入bug。Ok“不优雅”可能不是最好的选择。我的意思是cancel()发送了一个线程中断,但实际上并没有给我时间来正确调用job.cancel()。如果我创建一个未来任务调用