2012-06-04 160 views
4

我想调用一个HashSet的add函数有一些延迟,但没有阻塞当前线程。有没有简单的解决方案来实现这样的事情:如何使延迟非阻塞函数调用

Utils.sleep(1000, myHashSet.add(foo)); //added after 1 second 
//code here runs immediately without delay 
... 
+1

您的问题的直接答案如下。但是,试图做什么似乎相当不自然,这表明也许你应该寻找一个完全不同的解决方案。你想提供一些更多的上下文,为什么你想延迟添加? – Jochen

+0

我正在使用[Storm](https://github.com/nathanmarz/storm)来实现爬虫。抓取的URL由包含线程ID和板号的模式生成。抓取工具的性质使得每个电路板只能处理一个URL。我的HashSet包含当前可以抓取的所有主板的ID。对单个网址的抓取可能因为不同的原因而失败(线程被删除,404,...)。有些原因允许重试抓取。关于这些原因的信息被保存在不锁定的DB中,所以在决定是否重试之前应该有一些延迟。 – Thomas

+0

这听起来不必要的复杂。为什么爬网线程无法处理返回值,并且在发生可恢复故障时直接重试,或者至少将URL添加回地图(队列可能更适合此操作)。 – Jochen

回答

3

您可以使用ScheduledThreadPoolExecutor.schedule

ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1); 

exec.schedule(new Runnable() { 
      public void run() { 
       myHashSet.add(foo); 
      } 
    }, 1, TimeUnit.SECONDS); 

它将在一个单独的线程在1秒钟后执行代码。尽管如此,请注意myHashSet的并发修改。如果您从另一个线程同时修改集合或尝试迭代它,则可能会遇到问题,并且需要使用锁。

9

的单纯功能的解决办法是:

new Thread(new Runnable() { 
     public void run() { 
      try { Thread.sleep(1000); } 
      catch (InterruptedException ie) {} 
      myHashSet.add(foo); 
     } 
    }).start(); 

有少了很多比的ThreadPoolExecutor怎么回事幕后。 TPE可以方便地控制线程的数量,但是如果您正在分离大量睡眠或等待的线程,那么限制其数量可能会损害性能,而不仅仅是帮助。

如果您尚未处理此问题,并且您想同步myHashSet。请记住,你必须同步无处不在为此做任何好事。还有其他的方法来处理这个问题,比如Collections.synchronizedMap或者ConcurrentHashMap。