如何分别在n个线程中安排一些工作

时间:2017-11-07 13:01:16

标签: java multithreading

假设我有n个线程同时从共享队列中获取值:

public class WorkerThread implements Runnable{
        private BlockingQueue queue;
        private ArrayList<Integer> counts = new ArrayList<>();
        private int count=0;
        public void run(){
            while(true) {
                queue.pop();
                count++;
            }
        }
}

然后对于每个线程,我想每5秒计算它已经出列了多少项,然后将它存储在自己的列表中(计数) 我在这里看到Print "hello world" every X seconds如何每隔x秒运行一些代码:

Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask(){
    @Override
    public void run(){
        counts.add(count);
        count = 0
    }
}, 0, 5000);

这个问题是我无法访问计数变量和计数列表,除非它们是静态的。但我不希望它们是静态的,因为我不希望不同的线程共享这些变量。

有关如何处理此事的任何想法?

2 个答案:

答案 0 :(得分:1)

我认为不可能为您使用预定执行情况(TimerScheduledExecutorService),因为每个新的计划调用都会使用while循环创建新任务。因此,任务数量将不断增加。

如果您不需要在运行时访问此计数列表,我建议使用以下内容:

  static class Task implements Runnable {
    private final ThreadLocal<List<Integer>> counts = ThreadLocal.withInitial(ArrayList::new);
    private volatile List<Integer> result = new ArrayList<>();
    private BlockingQueue<Object> queue;

    public Task(BlockingQueue<Object> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      int count = 0;
      long start = System.nanoTime();
      try {
        while (!Thread.currentThread().isInterrupted()) {
          queue.take();
          count++;
          long end = System.nanoTime();
          if ((end - start) >= TimeUnit.SECONDS.toNanos(1)) {
            counts.get().add(count);
            count = 0;
            start = end;
          }
        }
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
      // the last value
      counts.get().add(count);
      // copy the result cause it's not possible
      // to access thread local variable outside of this thread
      result = counts.get();
    }

    public List<Integer> getCounts() {
      return result;
    }
  }

  public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    BlockingQueue<Object> blockingQueue = new LinkedBlockingQueue<>();
    Task t1 = new Task(blockingQueue);
    Task t2 = new Task(blockingQueue);
    Task t3 = new Task(blockingQueue);
    executorService.submit(t1);
    executorService.submit(t2);
    executorService.submit(t3);

    for (int i = 0; i < 50; i++) {
      blockingQueue.add(new Object());
      Thread.sleep(100);
    }
    // unlike shutdown() interrupts running threads
    executorService.shutdownNow();
    executorService.awaitTermination(1, TimeUnit.SECONDS);

    System.out.println("t1 " + t1.getCounts());
    System.out.println("t2 " + t2.getCounts());
    System.out.println("t3 " + t3.getCounts());

    int total = Stream.concat(Stream.concat(t1.getCounts().stream(), t2.getCounts().stream()), t3.getCounts().stream())
        .reduce(0, (a, b) -> a + b);
    // 50 as expected
    System.out.println(total);
  }

答案 1 :(得分:-1)

  • 为什么不是静态的AtomicLong?
  • 或者WorkerThread可以发布他们poped到TimerTask或其他地方? TimerTask会读取该信息吗?