Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.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_Callback_Notify_Executor - Fatal编程技术网

Java执行者:当任务完成时,如何在不阻塞的情况下得到通知?

Java执行者:当任务完成时,如何在不阻塞的情况下得到通知?,java,callback,notify,executor,Java,Callback,Notify,Executor,假设我有一个队列,队列中充满了我需要提交给执行器服务的任务。我要一次处理一个。我能想到的最简单的方法是: 从队列中获取任务 把它交给遗嘱执行人 调用。获取返回的未来并阻止,直到结果可用 从队列中获取另一个任务 然而,我试图避免完全阻塞。如果我有10000个这样的队列,它们需要一次处理一个任务,那么我将耗尽堆栈空间,因为它们中的大多数将保留阻塞的线程 我想要的是提交一个任务并提供一个在任务完成时调用的回调。我将使用该回调通知作为发送下一个任务的标志。(functionaljava和jetlang显

假设我有一个队列,队列中充满了我需要提交给执行器服务的任务。我要一次处理一个。我能想到的最简单的方法是:

  • 从队列中获取任务
  • 把它交给遗嘱执行人
  • 调用。获取返回的未来并阻止,直到结果可用
  • 从队列中获取另一个任务
  • 然而,我试图避免完全阻塞。如果我有10000个这样的队列,它们需要一次处理一个任务,那么我将耗尽堆栈空间,因为它们中的大多数将保留阻塞的线程

    我想要的是提交一个任务并提供一个在任务完成时调用的回调。我将使用该回调通知作为发送下一个任务的标志。(functionaljava和jetlang显然使用了这种非阻塞算法,但我无法理解它们的代码)

    除了编写自己的executor服务之外,如何使用JDK的java.util.concurrent实现这一点

    (为我提供这些任务的队列本身可能会阻塞,但这是一个稍后要解决的问题)

    使用

    它来自
    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