如何使线程等待特定条件

时间:2019-06-17 11:47:17

标签: java multithreading thread-safety

有一个线程计算素数并将其添加到集合中。

现在还有其他线程将执行bool isPrime(long n)方法。如果该方法包含数字(n),则只会查看该集合。

但是执行isPrime(...)的线程需要等到:

  • 已添加号码
  • 有一个大于n的数字,所以我知道n不能为素数。

在这种情况下,它仅允许通知线程。因此,在将每个数字添加到集合后,我都无法通知并检查其数字是否更高。

您能在不忙于等待的情况下给我一些有关这种等待条件的解释吗?

我只知道我可以让线程在对象上等待,其他线程可以通知它们,但是我无法理解这种行为,也许我只是以错误的方式思考。

2 个答案:

答案 0 :(得分:3)

这实际上取决于您的总体设计。

一个简单的解决方案将像这样工作:

  • 您有1个线程素生成器和n个线程素测试器
  • 最初,所有主要测试人员都致电wait()
  • 每次素数生成器添加一个新素数,它会通知所有素数测试者
  • 每个测试人员检查是否已经输入了号(或一个更大的号),或者测试员是否找到了其编号,或者知道“不在”。如果没有,它将再次调用wait()

该解决方案的巨大优势:原始生成器不需要知道有多少个原始测试器。它只是通知所有在公用监视器上等待的线程。

或者,最初生成器可以确切知道存在哪些最初测试器,以及他们负责多少。因此,它不会唤醒所有测试人员,而只会通知需要知道的人员。

请理解:您仅给出了一些模糊的要求,没有任何代码。因此,您会收到一个含糊的答案,没有任何代码。我的回答是为了启发您指导下一步的作业。

仅作记录:如果您想获取非常大的质数,那么使用列表是一个不好的选择。假设您的清单包含100万个素数。调用contains()的费用将随着条目数的增加而线性增加。因此,宁可使用可以快速查找元素(某种类型的集合/树)的集合,也可以快速访问集合中当前“最后一个”(最大)的数字。

答案 1 :(得分:0)

@GhostCat回答的基本思想变成了代码:

import java.util.HashSet;
import java.util.Set;

public class PrimeThreading {
    // All prime numbers found so far.
    private static final Set<Long> primes = new HashSet<>();
    // Last number checked by the generator.
    private static long numbersChecked = 0L;
    // The lock object.
    private static final Object lock = new Object();

    private static class PrimeGenerator implements Runnable {
        private final long maxNumber = Long.MAX_VALUE;

        @Override
        public void run() {
            // Generate all prime numbers from 2 to maxNumber
            for (long n = 2; n < maxNumber; n++) {
                // Naively test if n is prime.
                boolean isPrime = true;
                for (long i = 2; i * i < n; i++) {
                    if (n % i == 0) {
                        isPrime = false;
                        break;
                    }
                }
                synchronized (lock) {
                    if (isPrime) {
                        primes.add(n);
                    }
                    numbersChecked = n;
                    // Notify waiting threads
                    lock.notifyAll();
                }
            }
        }
    }

    private static boolean isPrime(long x) {
        synchronized (lock) {
            // Wait until number checked is greater than x
            while (x > numbersChecked) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    break;
                }
            }
            return primes.contains(x);
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new PrimeGenerator());
        thread.setDaemon(true);
        thread.start();

        System.out.println(isPrime(15_485_863));
    }
}