java - 并发检查集合是否为空

标签 java multithreading

我有这段代码:

private ConcurrentLinkedQueue<Interval> intervals = new ConcurrentLinkedQueue();
@Override
public void run(){
  while(!intervals.isEmpty()){
    //remove one interval
    //do calculations
    //add some intervals
  }
}

此代码同时由特定数量的线程执行。如您所见,循环应该继续进行,直到集合中没有更多的间隔为止,但是有一个问题。在每次迭代的开始,一个区间从集合中移除,最后一些区间可能被添加回同一个集合。

问题是,当一个线程在循环内时,集合可能会变空,因此其他试图进入循环的线程将无法做到这一点,并且会过早地完成它们的工作,即使集合 可能在第一个线程完成迭代后填充值。我希望线程数保持不变(或不超过某个数字 n),直到所有工作真正完成。

这意味着当前没有线程在循环中工作,并且集合中没有剩余元素。有哪些可能的方法来实现这一点?欢迎任何想法。

在我的具体案例中,解决此问题的一种方法是为每个线程提供原始集合的不同部分。但是在一个线程完成它的工作之后它就不会再被程序使用了,即使它可以帮助其他线程进行计算,所以我不喜欢这个解决方案,因为在其中利用机器的所有核心很重要我的问题。

这是我能想到的最简单的最小工作示例。可能会太长。

public class Test{   
   private ConcurrentLinkedQueue<Interval> intervals = new ConcurrentLinkedQueue();
   private int threadNumber;
   private Thread[] threads;
   private double result;

   public Test(int threadNumber){
      intervals.add(new Interval(0, 1));
      this.threadNumber = threadNumber;
      threads = new Thread[threadNumber];
   }

   public double find(){
      for(int i = 0; i < threadNumber; i++){
         threads[i] = new Thread(new Finder());
         threads[i].start();
      }
      try{
         for(int i = 0; i < threadNumber; i++){
            threads[i].join();
         }
      }
      catch(InterruptedException e){
         System.err.println(e);
      }
      return result;
   }   

   private class Finder implements Runnable{   
      @Override
      public void run(){
         while(!intervals.isEmpty()){
            Interval interval = intervals.poll();
            if(interval.high - interval.low > 1e-6){    
               double middle = (interval.high + interval.low) / 2;
               boolean something = true;
               if(something){
                  intervals.add(new Interval(interval.low + 0.1, middle - 0.1));
                  intervals.add(new Interval(middle + 0.1, interval.high - 0.1));
               }
               else{
                  intervals.add(new Interval(interval.low + 0.1, interval.high - 0.1));
               }
            }
         }
      }
   }

   private class Interval{
      double low;
      double high;
      public Interval(double low, double high){
         this.low = low;
         this.high = high;
      }
   }
}

您可能需要了解的有关该程序的信息:在每次迭代之后,间隔应该消失(因为它太小)、变小或分成两个较小的间隔。不留间隔后工作结束。此外,我应该能够限制使用某个数字 n 执行此工作的线程数。实际程序通过划分区间并使用某些规则丢弃那些区间中不能包含最大值的部分来寻找某个函数的最大值,但这与我的问题无关。

最佳答案

CompletableFuture 类也是此类任务的有趣解决方案。 它会自动将工作负载分配给多个工作线程。

static CompletableFuture<Integer> fibonacci(int n) {
  if(n < 2) return CompletableFuture.completedFuture(n);
  else {
    return CompletableFuture.supplyAsync(() -> {
      System.out.println(Thread.currentThread());
      CompletableFuture<Integer> f1 = fibonacci(n - 1);
      CompletableFuture<Integer> f2 = fibonacci(n - 2);
      return f1.thenCombineAsync(f2, (a, b) -> a + b);
    }).thenComposeAsync(f -> f);
  }
}

public static void main(String[] args) throws Exception {
  int fib = fibonacci(10).get();
  System.out.println(fib);
}

关于java - 并发检查集合是否为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30006677/

相关文章:

java - 在 POST 请求中发送响应

java - 在 Java 中检查一组字符串中的包含

Python多线程队列剩余 "empty"

java - Sql 抛出 org.springframework.jdbc.BadSqlGrammarException(PreparedStatementCallback; 错误的 SQL 语法

java - 为什么会出现 SocketException?

java - 在 Java 中使用日期作为 TreeMultimap 的键时记录丢失

python - 如何在 Python 3 中引用线程?

c++ - 改进 InterlockedCompareExchange() 的原子读取

C# .net For() 步骤?

c# - 多线程并行编程示例