【问题标题】:How can I tell other threads in threadpool to stop after one thread completes the task?一个线程完成任务后,如何告诉线程池中的其他线程停止?
【发布时间】:2017-03-15 18:16:34
【问题描述】:

这是我的代码:

class Processor implements Runnable {

    private int id;
    private Integer interaction;
    private Set<Integer> subset;
    Iterator<Integer> iterator;
    ArrayList<Integer> par;

    public Processor(int id, Integer interaction, Set<Integer> subset, Iterator<Integer> iterator, ArrayList<Integer> par) {
        this.id = id;
        this.interaction = interaction;
        this.subset = subset;
        this.par = par;
        this.iterator = iterator;
    }

    public void run() {
        System.out.println("Starting: " + this.id);
        if (this.par.contains(this.interaction)) {
            this.subset.add(this.interaction);
            increaseScore(this.subset);
            if (!this.subset.contains(this.interaction)) {
                //TELL ALL OTHER THREADS TO STOP WHILE THIS THREAD REMOVES THE VALUE FROM THE ITERATOR
                iterator.remove();
            }
        }

        System.out.println("Completed: " + this.id);

    }
}

public class ConcurrentApp {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(4);
        ArrayList<Integer> par1 = new ArrayList < Integer > ();
        long start = System.nanoTime();

        int i = 1;
        while ((par1.size() > i)) {
            for (Iterator<Integer> iterator = par1.iterator(); iterator.hasNext();) {
                Integer interaction = iterator.next();
                ArrayList<Integer> removed = new ArrayList<Integer> (par1);
                removed.remove(interaction);
                ArrayList<Set<Integer>> subsets = getSubsets(removed, i);
                for (int j = 0; j < subsets.size(); j++) {
                    executor.submit(new Processor(j, interaction, subsets.get(j), iterator, par1));
                }
                executor.shutdown();
                System.out.println("All tasks submitted");
                try {
                    executor.awaitTermination(1, TimeUnit.DAYS);
                } catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("All tasks completed");
            i++;
        }
        long end = System.nanoTime();

        System.out.println("Program Completed in: " + (end - start) * 0.000000001);

    }
}

我的代码流程如下:

  1. 从一个名为 par 的整数数组列表开始,遍历此集合中的每个元素(我们将称为 A)

  2. 从par中去掉A得到B

  3. 查找大小为 i 的所有子集(在 1 到 par.size() 的范围内)

  4. [多线程] 对于每个大小为 i 的子集,在 A 中加回以获得新的集合 C。然后找到删除时 C 的得分增加最多的值。 [条件]如果该值为 A,则从 par 中删除 A 并移动到 par 中的下一个元素。如果 A 没有删除任何大小为 i 的子集,则继续到 par 中的下一个元素。

我的意图是让每个线程使用其中一个子集并执行上述多线程步骤,直到其中一个线程满足条件。我认为我正确地实现了这一点,但由于我是并发编程的新手,所以我会欣赏第二组眼睛。

问题 1: 在上面的多线程步骤中,我怎样才能告诉线程池中的所有其他工作线程停止他们的任务并在单个线程遇到时返回线程池 条件

问题 2: 有没有办法让多个线程同时处理不同大小的子集的不同集合(因此一次有多个 i 值)并让多个线程执行 上面的多线程步骤对于给定的一组子集(这是我已经完成的)?本质上,这就像把我的整个工作分成两个任务:任务 1 是查看大小为 1、2、3...par.size() 的子集集,任务 2 是查看集合中的每个元素子集。

感谢您的帮助!

【问题讨论】:

    标签: java multithreading concurrency java.util.concurrent


    【解决方案1】:

    Q1:使用 volatile 静态变量(可能是 volatile AtomicLong),所有线程都可以检查完成情况,并在完成活动时更新。

    Q2:这绝对是可能的。您已经设置了一个 Runnable,可以使用您的 Shapes 和子集大小的范围来处理。但据我所见,这可能是矫枉过正:任务 2(您已完成的部分)将需要比任务 1 更多的处理能力,因此您不妨保持原样现在

    如果我看错了你的问题,请告诉我

    【讨论】:

    • 对于 Q1 的回复,您的意思是我可以将布尔 volatile 变量设置为 False,然后有一个 while 循环在处理器的“运行”方法中不断检查这个变量。那么当线程满足条件时,我可以将变量设置为True?
    • @Chandra_Rathnam 是的,就是这样
    • 有道理!但是,当满足 Condition 时,在任务 2 上工作的线程是否仍会执行它们正在执行的任何计算(即分数计算,这可能非常耗时),直到它们到达循环结束?还是一个while循环检查它的条件是否在每一行代码中都满足(对不起这个基本问题)所以如果我改变静态易失变量的值,它会立即退出那个线程的while循环?
    • 它不会检查每一行代码,但这是一件好事。通过在 while 循环中检查一次......甚至在 while 循环中每 50 或 100 次迭代检查一次(取决于每次迭代的强度),您实际上将获得更高的性能 - 这是检查频率和检查频率之间的平衡该检查正在延迟常规处理
    • 嗯是有道理的。非常感谢您的解释。我很感激不仅能得到答案,还能理解这一切是如何运作的:)。我得到的最好的回应!
    【解决方案2】:

    问题 1: 在上面的多线程步骤中,如何告诉线程池中的所有其他工作线程在单个线程满足 Condition 时停止它们的任务并返回线程池?

    使用ExecutorServiceinvokeAny API

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout,
                    TimeUnit unit)
             throws InterruptedException,
                    ExecutionException,
                    TimeoutException
    

    执行给定任务,返回已成功完成的任务的结果(即,不抛出异常),如果在给定超时过去之前有任何操作。正常或异常返回时,取消未完成的任务。如果在此操作进行时修改了给定的集合,则此方法的结果是不确定的。

    问题 2: 有没有办法让多个线程同时处理不同大小的子集的不同集合(因此一次有多个 i 值)并让多个线程执行上面的多线程步骤对于给定的一组子集(这是我已经完成的)?

    您可以使用 .如果您在上述实施过程中遇到任何问题,请分享您的问题。即使您想等待所有任务完成,您也可以使用invokeAll。如果你想提高性能,可以使用ForkJoinPool

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 2019-06-22
      • 2023-03-29
      相关资源
      最近更新 更多