jjzjj

java - 线程池处理 'duplicate' 任务

coder 2024-03-20 原文

我想并行执行一些不同的任务,但有一个概念,即如果任务已经排队或正在处理,则不会重新排队。我已经阅读了一些关于 Java API 的内容,并提出了下面的代码,它似乎可以工作。 任何人都可以阐明我使用的方法是否是最好的方法。任何危险(线程安全?)或更好的方法来做到这一点? 代码如下:

import java.util.HashMap;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestExecution implements Runnable {
   String key1;
   String key2;   
   static HashMap<TestExecution, Future<?>> executions = new HashMap<TestExecution, Future<?>>();
   static LinkedBlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>();
   static ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 5, 1, TimeUnit.MINUTES, q);

   public static void main(String[] args) {
      try {
         execute(new TestExecution("A", "A"));
         execute(new TestExecution("A", "A"));
         execute(new TestExecution("B", "B"));
         Thread.sleep(8000);
         execute(new TestExecution("B", "B"));
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

   static boolean execute(TestExecution e) {
      System.out.println("Handling "+e.key1+":"+e.key2);
      if (executions.containsKey(e)) {
         Future<?> f = (Future<?>) executions.get(e);
         if (f.isDone()) {
            System.out.println("Previous execution has completed");
            executions.remove(e);
         } else {
            System.out.println("Previous execution still running");
            return false;
         }         
      }
      else {
         System.out.println("No previous execution");
      }
      Future<?> f = tpe.submit(e);
      executions.put(e, f);            
      return true;
   }

   public TestExecution(String key1, String key2) {
      this.key1 = key1;
      this.key2 = key2;      
   }

   public boolean equals(Object obj)
   {
       if (obj instanceof TestExecution)
       {
          TestExecution t = (TestExecution) obj;
           return (key1.equals(t.key1) && key2.equals(t.key2));           
       }       
       return false;
   }

   public int hashCode ()
   {
      return key1.hashCode()+key2.hashCode();
   }

   public void run() {      
      try {
         System.out.println("Start processing "+key1+":"+key2);
         Thread.sleep(4000);
         System.out.println("Finish processing "+key1+":"+key2);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }      
   }              
}

跟进以下评论:
计划是触发任务执行将由 cron 调用 RESTful web 服务来处理。例如,下面是每天 9:30 触发的一项任务的设置,以及每两分钟安排的另一项任务。

0/2 * * * * restclient.pl key11 key12 
30 09 * * * restclient.pl key21 key22

在这种情况下,如果任务 key11:key12 正在运行,或者已经排队等待运行,我不想让另一个实例排队。我知道我们还有其他计划安排选项,但我们倾向于将 cron 用于其他任务,所以我想尽量保留这一点。

第二次更新。为了回应目前的评论,我已经重写了代码,您能否评论以下更新解决方案的任何问题?

import java.util.concurrent.LinkedBlockingQueue;

public class TestExecution implements Runnable {
   String key1;
   String key2;      
   static TestThreadPoolExecutor tpe = new TestThreadPoolExecutor(new LinkedBlockingQueue<Runnable>());

   public static void main(String[] args) {
      try {
         tpe.execute(new TestExecution("A", "A"));
         tpe.execute(new TestExecution("A", "A"));
         tpe.execute(new TestExecution("B", "B"));
         Thread.sleep(8000);
         tpe.execute(new TestExecution("B", "B"));
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }

   public TestExecution(String key1, String key2) {
      this.key1 = key1;
      this.key2 = key2;      
   }

   public boolean equals(Object obj)
   {
       if (obj instanceof TestExecution)
       {
          TestExecution t = (TestExecution) obj;
           return (key1.equals(t.key1) && key2.equals(t.key2));           
       }       
       return false;
   }

   public int hashCode ()
   {
      return key1.hashCode()+key2.hashCode();
   }

   public void run() {      
      try {
         System.out.println("Start processing "+key1+":"+key2);
         Thread.sleep(4000);
         System.out.println("Finish processing "+key1+":"+key2);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }      
   }
}


import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class TestThreadPoolExecutor extends ThreadPoolExecutor {
   Set<Runnable> executions = Collections.synchronizedSet(new HashSet<Runnable>());

   public TestThreadPoolExecutor(LinkedBlockingQueue<Runnable> q) {      
      super(2, 5, 1, TimeUnit.MINUTES, q);      
   }

   public void execute(Runnable command) {
      if (executions.contains(command)) {
         System.out.println("Previous execution still running");
         return;
      }
      else {
         System.out.println("No previous execution");
      }
      super.execute(command);      
      executions.add(command);      
   }

   protected void afterExecute(Runnable r, Throwable t) {
      super.afterExecute(r, t);        
      executions.remove(r);
   }      
}

最佳答案

下面是我将如何处理和避免重复

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.*;

public class TestExecution implements Callable<Void> {
    private static final ThreadPoolExecutor TPE = new ThreadPoolExecutor(2, 5, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
    private static final Set<TestExecution> TE_SET = Collections.newSetFromMap(new ConcurrentHashMap<TestExecution, Boolean>());

    private final String key1;
    private final String key2;

    public static void main(String... args) throws InterruptedException {
        new TestExecution("A", "A").execute();
        new TestExecution("A", "A").execute();
        new TestExecution("B", "B").execute();
        Thread.sleep(8000);
        new TestExecution("A", "A").execute();
        new TestExecution("B", "B").execute();
        new TestExecution("B", "B").execute();
        TPE.shutdown();
    }

    public TestExecution(String key1, String key2) {
        this.key1 = key1;
        this.key2 = key2;
    }

    void execute() {
        if (TE_SET.add(this)) {
            System.out.println("Handling " + this);
            TPE.submit(this);
        } else {
            System.out.println("... ignoring duplicate " + this);
        }
    }

    public boolean equals(Object obj) {
        return obj instanceof TestExecution &&
                key1.equals(((TestExecution) obj).key1) &&
                key2.equals(((TestExecution) obj).key2);
    }

    public int hashCode() {
        return key1.hashCode() * 31 + key2.hashCode();
    }

    @Override
    public Void call() throws InterruptedException {
        if (!TE_SET.remove(this)) {
            System.out.println("... dropping duplicate " + this);
            return null;
        }
        System.out.println("Start processing " + this);
        Thread.sleep(4000);
        System.out.println("Finish processing " + this);
        return null;
    }

    public String toString() {
        return key1 + ':' + key2;
    }
}

打印

Handling A:A
... ignoring duplicate A:A
Handling B:B
Start processing A:A
Start processing B:B
Finish processing A:A
Finish processing B:B
Handling A:A
Handling B:B
Start processing A:A
Start processing B:B
... ignoring duplicate B:B
Finish processing B:B
Finish processing A:A

关于java - 线程池处理 'duplicate' 任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8905780/

有关java - 线程池处理 'duplicate' 任务的更多相关文章

  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-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  5. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  6. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  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 - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  9. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  10. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

随机推荐