【问题标题】:How can I schedule some work in n threads separately如何分别在 n 个线程中安排一些工作
【发布时间】:2017-11-07 13:01:16
【问题描述】:

假设我有 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);

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

关于如何处理这个问题的任何想法?

【问题讨论】:

  • Timer t = ... 代码块放在while (true) 上方编译(除了你需要.take 而不是.pop),所以一切都应该没问题。但是由于定时器任务会在另一个线程中执行,所以使用AtomicInteger countgetAndSet(0)方法。
  • 在任务执行期间或完成后,您在运行时是否需要此信息?
  • 如果我把 Timer t=... 放在 while 上面,如果我只使用 1 个线程,它会起作用。我想使用 n 个线程。例如,我有线程 1 和线程 2。然后在 5 秒内,线程 1 从队列中取了 1000 个值,线程 2 取了 1100。我需要线程 1 将 1000 存储在自己的列表中,线程 2 将 1100 存储在也有自己的清单。我不想在线程之间共享计数变量。我需要在任务执行期间收集这些信息。完成后我需要它,只是为了检查线程在执行过程中的工作是否大致相同。
  • @Mr.Liu 它将完全按照您的描述工作,对于多个线程以及单个线程 - 每个 Runnable 将有自己的 count

标签: java multithreading


【解决方案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);
  }

【讨论】:

    【解决方案2】:
    • 为什么不是静态 AtomicLong?
    • 或者 WorkerThread(s) 可以将他们弹出的消息发布到 TimerTask 或其他地方? TimerTask 会读取该信息吗?

    【讨论】:

    • AtomicLong 有什么用?我不希望每个线程都分享自己的计数。你能解释一下 WorkerThread(s) 如何将它们的值发布到 TimerTask 吗?
    • 如果您需要澄清或向 OP 提问,请使用 cmets(如果不能,请等到您有足够的声望)。否则,请将您的答案变成真正的答案,而不是一组问题。
    • 我的回答更多的是一些建议——不是真正的问题。 WorkerThread 可以将 TimerTask 作为参数并调用方法。
    猜你喜欢
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 2020-05-18
    • 1970-01-01
    相关资源
    最近更新 更多