Java执行者:当任务完成时,如何在不阻塞的情况下得到通知?
假设我有一个队列,队列中充满了我需要提交给执行器服务的任务。我要一次处理一个。我能想到的最简单的方法是:Java执行者:当任务完成时,如何在不阻塞的情况下得到通知?,java,callback,notify,executor,Java,Callback,Notify,Executor,假设我有一个队列,队列中充满了我需要提交给执行器服务的任务。我要一次处理一个。我能想到的最简单的方法是: 从队列中获取任务 把它交给遗嘱执行人 调用。获取返回的未来并阻止,直到结果可用 从队列中获取另一个任务 然而,我试图避免完全阻塞。如果我有10000个这样的队列,它们需要一次处理一个任务,那么我将耗尽堆栈空间,因为它们中的大多数将保留阻塞的线程 我想要的是提交一个任务并提供一个在任务完成时调用的回调。我将使用该回调通知作为发送下一个任务的标志。(functionaljava和jetlang显
java.util.concurrent
,这正是等待多个线程完成执行后再继续的方式
为了实现您所关注的回调效果,这确实需要一些额外的工作。也就是说,您自己在一个单独的线程中处理这个问题,该线程使用CountDownLatch
并等待它,然后继续通知您需要通知的内容。本机不支持回调或类似的效果
编辑:现在我进一步理解了你的问题,我认为你做得太过分了,不必要。如果您使用常规,则将所有任务都交给它,它将以本机方式排队。定义一个回调接口,以接收您希望在完成通知中传递的任何参数。然后在任务结束时调用它 您甚至可以为可运行任务编写一个通用包装器,并将其提交给
ExecutorService
。或者,请参见下面的Java8内置的机制
class CallbackTask implements Runnable {
private final Runnable task;
private final Callback callback;
CallbackTask(Runnable task, Callback callback) {
this.task = task;
this.callback = callback;
}
public void run() {
task.run();
callback.complete();
}
}
使用Java8,它包含了一种更复杂的方法来组成管道,在管道中可以异步和有条件地完成进程。下面是一个精心设计但完整的通知示例
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class GetTaskNotificationWithoutBlocking {
public static void main(String... argv) throws Exception {
ExampleService svc = new ExampleService();
GetTaskNotificationWithoutBlocking listener = new GetTaskNotificationWithoutBlocking();
CompletableFuture<String> f = CompletableFuture.supplyAsync(svc::work);
f.thenAccept(listener::notify);
System.out.println("Exiting main()");
}
void notify(String msg) {
System.out.println("Received message: " + msg);
}
}
class ExampleService {
String work() {
sleep(7000, TimeUnit.MILLISECONDS); /* Pretend to be busy... */
char[] str = new char[5];
ThreadLocalRandom current = ThreadLocalRandom.current();
for (int idx = 0; idx < str.length; ++idx)
str[idx] = (char) ('A' + current.nextInt(26));
String msg = new String(str);
System.out.println("Generated message: " + msg);
return msg;
}
public static void sleep(long average, TimeUnit unit) {
String name = Thread.currentThread().getName();
long timeout = Math.min(exponential(average), Math.multiplyExact(10, average));
System.out.printf("%s sleeping %d %s...%n", name, timeout, unit);
try {
unit.sleep(timeout);
System.out.println(name + " awoke.");
} catch (InterruptedException abort) {
Thread.currentThread().interrupt();
System.out.println(name + " interrupted.");
}
}
public static long exponential(long avg) {
return (long) (avg * -Math.log(1 - ThreadLocalRandom.current().nextDouble()));
}
}
import java.util.concurrent.CompletableFuture;
导入java.util.concurrent.ThreadLocalRandom;
导入java.util.concurrent.TimeUnit;
公共类GetTaskKnotificationwithout阻塞{
公共静态void main(字符串…argv)引发异常{
ExampleService svc=新的ExampleService();
GetTaskNotificationWithoutBlocking侦听器=新建GetTaskNotificationWithoutBlocking();
CompletableFuture f=CompletableFuture.supplyAsync(svc::work);
f、 然后接受(侦听器::notify);
System.out.println(“退出main()”;
}
无效通知(字符串消息){
System.out.println(“收到的消息:“+msg”);
}
}
类示例服务{
弦乐作品(){
睡眠(7000,时间单位。毫秒);/*假装很忙*/
char[]str=新字符[5];
ThreadLocalRandom current=ThreadLocalRandom.current();
对于(int-idx=0;idx
如果要确保不会同时运行任何任务,请使用。任务将按照提交的顺序进行处理。您甚至不需要保存任务,只需将它们提交给exec。ThreadPoolExecutor
还有beforexecute
和afterExecute
钩子方法,您可以覆盖和使用它们。以下是ThreadPoolExecutor
的描述
钩子法
此类提供受保护的可重写方法和在执行每个任务之前和之后调用的方法。这些可用于操纵执行环境;例如,重新初始化ThreadLocals
、收集统计信息或添加日志项。此外,可以重写方法以执行执行器完全终止后需要执行的任何特殊处理。如果钩子或回调方法抛出异常,内部工作线程可能会失败并突然终止
您可以扩展FutureTask
类,覆盖done()
方法,然后将FutureTask
对象添加到ExecutorService
,这样done()
方法将在FutureTask
立即完成时调用。使用并添加回调。参考网站:
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
public Explosion call() {
return pushBigRedButton();
}
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
// we want this handler to run immediately after we push the big red button!
public void onSuccess(Explosion explosion) {
walkAwayFrom(explosion);
}
public void onFailure(Throwable thrown) {
battleArchNemesis(); // escaped the explosion!
}
});
listengExecutorService=MoreExecutors.listengDecorator(Executors.newFixedThreadPool(10));
ListenableFuture explosion=service.submit(new Callable()){
公众爆炸电话(){
返回pushBigRedButton();
}
});
Futures.addCallback(爆炸,新未来回调(){
//我们希望这个处理程序在按下红色大按钮后立即运行!
成功时的公共空间(爆炸){
从(爆炸)中逃走;
}
失败时公共无效(可丢弃){
战神报应();//逃过了爆炸!
}
});
中的
CompletableFuture.supplyAsync(
userService::listUsers
).thenApply(
this::mapUsersToUserViews
).thenAccept(
this::updateView
).exceptionally(
throwable -> { showErrorDialogFor(throwable); return null; }
);
private static Primes primes = new Primes();
public static void main(String[] args) throws InterruptedException {
getPrimeAsync((p) ->
System.out.println("onPrimeListener; p=" + p));
System.out.println("Adios mi amigito");
}
public interface OnPrimeListener {
void onPrime(int prime);
}
public static void getPrimeAsync(OnPrimeListener listener) {
CompletableFuture.supplyAsync(primes::getNextPrime)
.thenApply((prime) -> {
System.out.println("getPrimeAsync(); prime=" + prime);
if (listener != null) {
listener.onPrime(prime);
}
return prime;
});
}
getPrimeAsync(); prime=241
onPrimeListener; p=241
Adios mi amigito
public class MyAsyncCallable<V> implements Callable<V> {
CallbackInterface ci;
public MyAsyncCallable(CallbackInterface ci) {
this.ci = ci;
}
public V call() throws Exception {
System.out.println("Call of MyCallable invoked");
System.out.println("Result = " + this.ci.doSomething(10, 20));
return (V) "Good job";
}
}
public interface CallbackInterface {
public int doSomething(int a, int b);
}
ExecutorService ex = Executors.newFixedThreadPool(2);
MyAsyncCallable<String> mac = new MyAsyncCallable<String>((a, b) -> a + b);
ex.submit(mac);
// ListenableFuture1: Open Database
ListenableFuture<Database> database = service.submit(() -> openDatabase());
// ListenableFuture2: Query Database for Cursor rows
ListenableFuture<Cursor> cursor =
Futures.transform(database, database -> database.query(table, ...));
// ListenableFuture3: Convert Cursor rows to List<Foo>
ListenableFuture<List<Foo>> fooList =
Futures.transform(cursor, cursor -> cursorToFooList(cursor));
// Final Callback: Handle the success/errors when final future completes
Futures.addCallback(fooList, new FutureCallback<List<Foo>>() {
public void onSuccess(List<Foo> foos) {
doSomethingWith(foos);
}
public void onFailure(Throwable thrown) {
log.error(thrown);
}
});
import java.util.concurrent.*;
import java.util.*;
public class CallBackDemo{
public CallBackDemo(){
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(5);
try{
for ( int i=0; i<5; i++){
Callback callback = new Callback(i+1);
MyCallable myCallable = new MyCallable((long)i+1,callback);
Future<Long> future = service.submit(myCallable);
//System.out.println("future status:"+future.get()+":"+future.isDone());
}
}catch(Exception err){
err.printStackTrace();
}
service.shutdown();
}
public static void main(String args[]){
CallBackDemo demo = new CallBackDemo();
}
}
class MyCallable implements Callable<Long>{
Long id = 0L;
Callback callback;
public MyCallable(Long val,Callback obj){
this.id = val;
this.callback = obj;
}
public Long call(){
//Add your business logic
System.out.println("Callable:"+id+":"+Thread.currentThread().getName());
callback.callbackMethod();
return id;
}
}
class Callback {
private int i;
public Callback(int i){
this.i = i;
}
public void callbackMethod(){
System.out.println("Call back:"+i);
// Add your business logic
}
}
creating service
Callable:1:pool-1-thread-1
Call back:1
Callable:3:pool-1-thread-3
Callable:2:pool-1-thread-2
Call back:2
Callable:5:pool-1-thread-5
Call back:5
Call back:3
Callable:4:pool-1-thread-4
Call back:4
//System.out.println("future status:"+future.get()+":"+future.isDone());
Executors.newCachedThreadPool()
Executors.newWorkStealingPool()
ThreadPoolExecutor