草庐IT

java - 如何在 ExecutorService.shutdown() 之后立即运行未完成的任务?

coder 2023-08-31 原文

我有一个 ScheduledExecutorService,任务计划在一小时内执行。如何获取未完成任务的列表以便强制它们立即运行?

我相信 shutdown() 将等待一个小时,看起来 shutdownNow() 返回一个无法运行的 Runnables 列表,因为 Runnable 实现检查Executor 状态,当它注意到它已经关闭时,Runnable 拒绝运行。有关实际实现,请参阅 ScheduledThreadPoolExecutor.ScheduledFutureTask.run()

有什么想法吗?

最佳答案

我采纳了 Mark Peters 的回答,实现了所有抽象方法,添加了线程安全,并尝试尽可能尊重底层的 ScheduledThreadPoolExecutor 配置。

/**
 * Overrides shutdown() to run outstanding tasks immediately.
 * 
 * @author Gili Tzabari
 */
public class RunOnShutdownScheduledExecutorService extends AbstractExecutorService
    implements ScheduledExecutorService
{
    private final ScheduledExecutorService delegate;
    private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
    private final ExecutorService immediateService;
    private final ConcurrentMap<Future<?>, Callable<?>> tasks = Maps.newConcurrentMap();

    /**
     * Creates a new RunOnShutdownScheduledExecutorService.
     * 
     * @param delegate the executor to delegate to
     */
    public RunOnShutdownScheduledExecutorService(ScheduledExecutorService delegate)
    {
        Preconditions.checkNotNull(delegate, "delegate may not be null");

        this.delegate = delegate;
        if (delegate instanceof ScheduledThreadPoolExecutor)
        {
            this.scheduledThreadPoolExecutor = (ScheduledThreadPoolExecutor) delegate;
            this.immediateService = Executors.newFixedThreadPool(scheduledThreadPoolExecutor.
                getCorePoolSize(), scheduledThreadPoolExecutor.getThreadFactory());
        }
        else
        {
            scheduledThreadPoolExecutor = null;
            this.immediateService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().
                setNameFormat(RunOnShutdownScheduledExecutorService.class.getName() + "-%d").build());
        }
    }

    @Override
    public boolean isShutdown()
    {
        return delegate.isShutdown();
    }

    @Override
    public boolean isTerminated()
    {
        return delegate.isTerminated();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
    {
        long before = System.nanoTime();
        if (!delegate.awaitTermination(timeout, unit))
            return false;
        long after = System.nanoTime();
        long timeLeft = timeout - unit.convert(after - before, TimeUnit.NANOSECONDS);
        return immediateService.awaitTermination(timeLeft, unit);
    }

    @Override
    public void execute(Runnable command)
    {
        delegate.execute(command);
    }

    @Override
    public ScheduledFuture<?> schedule(final Runnable command, long delay, TimeUnit unit)
    {
        CleaningRunnable decorated = new CleaningRunnable(command);
        ScheduledFuture<?> future = delegate.schedule(decorated, delay, unit);
        decorated.setFuture(future);
        tasks.put(future, Executors.callable(command));
        return new CleaningScheduledFuture<>(future);
    }

    @Override
    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
    {
        CallableWithFuture<V> decorated = new CallableWithFuture<>(callable);
        ScheduledFuture<V> future = delegate.schedule(decorated, delay, unit);
        decorated.setFuture(future);
        tasks.put(future, callable);
        return new CleaningScheduledFuture<>(future);
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
        TimeUnit unit)
    {
        CleaningRunnable decorated = new CleaningRunnable(command);
        ScheduledFuture<?> future = delegate.scheduleAtFixedRate(decorated, initialDelay, period, unit);
        decorated.setFuture(future);
        tasks.put(future, Executors.callable(command));
        return new CleaningScheduledFuture<>(future);
    }

    @Override
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,
        TimeUnit unit)
    {
        CleaningRunnable decorated = new CleaningRunnable(command);
        ScheduledFuture<?> future =
            delegate.scheduleWithFixedDelay(decorated, initialDelay, delay, unit);
        decorated.setFuture(future);
        tasks.put(future, Executors.callable(command));
        return new CleaningScheduledFuture<>(future);
    }

    @Override
    public synchronized void shutdown()
    {
        if (delegate.isShutdown())
            return;
        if (scheduledThreadPoolExecutor != null)
        {
            // WORKAROUND: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7069418
            //
            // Cancel waiting scheduled tasks, otherwise executor won't shut down
            scheduledThreadPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
        }
        delegate.shutdown();
        // Users will not be able to cancel() Futures past this point so we're guaranteed that
        // "tasks" will not be modified.

        final List<Callable<?>> outstandingTasks = Lists.newArrayList();
        for (Map.Entry<Future<?>, Callable<?>> entry: tasks.entrySet())
        {
            Future<?> future = entry.getKey();
            Callable<?> task = entry.getValue();

            if (future.isDone() && future.isCancelled())
            {
                // Task called by the underlying executor, not the user. See CleaningScheduledFuture.
                outstandingTasks.add(task);
            }
        }
        tasks.clear();
        if (outstandingTasks.isEmpty())
        {
            immediateService.shutdown();
            return;
        }

        immediateService.submit(new Callable<Void>()
        {
            @Override
            public Void call() throws Exception
            {
                delegate.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

                // Execute outstanding tasks only after the delegate executor finishes shutting down
                for (Callable<?> task: outstandingTasks)
                    immediateService.submit(task);
                immediateService.shutdown();
                return null;
            }
        });
    }

    @Override
    public List<Runnable> shutdownNow()
    {
        return delegate.shutdownNow();
    }

    /**
     * A Runnable that removes its future when running.
     */
    private class CleaningRunnable implements Runnable
    {
        private final Runnable delegate;
        private Future<?> future;

        /**
         * Creates a new RunnableWithFuture.
         * 
         * @param delegate the Runnable to delegate to
         * @throws NullPointerException if delegate is null
         */
        public CleaningRunnable(Runnable delegate)
        {
            Preconditions.checkNotNull(delegate, "delegate may not be null");

            this.delegate = delegate;
        }

        /**
         * Associates a Future with the runnable.
         * 
         * @param future a future
         */
        public void setFuture(Future<?> future)
        {
            this.future = future;
        }

        @Override
        public void run()
        {
            tasks.remove(future);
            delegate.run();
        }
    }

    /**
     * A Callable that removes its future when running.
     */
    private class CallableWithFuture<V> implements Callable<V>
    {
        private final Callable<V> delegate;
        private Future<V> future;

        /**
         * Creates a new CallableWithFuture.
         * 
         * @param delegate the Callable to delegate to
         * @throws NullPointerException if delegate is null
         */
        public CallableWithFuture(Callable<V> delegate)
        {
            Preconditions.checkNotNull(delegate, "delegate may not be null");

            this.delegate = delegate;
        }

        /**
         * Associates a Future with the runnable.
         * 
         * @param future a future
         */
        public void setFuture(Future<V> future)
        {
            this.future = future;
        }

        @Override
        public V call() throws Exception
        {
            tasks.remove(future);
            return delegate.call();
        }
    }

    /**
     * A ScheduledFuture that removes its future when canceling.
     * 
     * This allows us to differentiate between tasks canceled by the user and the underlying
     * executor. Tasks canceled by the user are removed from "tasks".
     * 
     * @param <V> The result type returned by this Future
     */
    private class CleaningScheduledFuture<V> implements ScheduledFuture<V>
    {
        private final ScheduledFuture<V> delegate;

        /**
         * Creates a new MyScheduledFuture.
         * 
         * @param delegate the future to delegate to
         * @throws NullPointerException if delegate is null
         */
        public CleaningScheduledFuture(ScheduledFuture<V> delegate)
        {
            Preconditions.checkNotNull(delegate, "delegate may not be null");

            this.delegate = delegate;
        }

        @Override
        public long getDelay(TimeUnit unit)
        {
            return delegate.getDelay(unit);
        }

        @Override
        public int compareTo(Delayed o)
        {
            return delegate.compareTo(o);
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning)
        {
            boolean result = delegate.cancel(mayInterruptIfRunning);

            if (result)
            {
                // Tasks canceled by users are removed from "tasks"
                tasks.remove(delegate);
            }
            return result;
        }

        @Override
        public boolean isCancelled()
        {
            return delegate.isCancelled();
        }

        @Override
        public boolean isDone()
        {
            return delegate.isDone();
        }

        @Override
        public V get() throws InterruptedException, ExecutionException
        {
            return delegate.get();
        }

        @Override
        public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException,
            TimeoutException
        {
            return delegate.get(timeout, unit);
        }
    }
}

关于java - 如何在 ExecutorService.shutdown() 之后立即运行未完成的任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6767906/

有关java - 如何在 ExecutorService.shutdown() 之后立即运行未完成的任务?的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  6. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  7. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  8. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  9. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  10. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

随机推荐