首页 > 解决方案 > 当其中一个找到素数时如何停止线程

问题描述

当找到一个素数时,我必须阻止它。当我在 之前使用synchronizedwhile时,只会发生一个线程进程。但是,应该发生多个线程操作,但是当找到素数时,所有线程都应该停止。

控制部分的初始值i已更改。

我想要做的是使用锁定和同步找到素数。

public abstract class NumberGenerator {

    private boolean isStop;

    public abstract int generateNumber();

    public void stop() {
        this.isStop = true;
    }

    public boolean isStopped() {
        return isStop;
    }

}

public class IntegerNumberGenerator extends NumberGenerator {

    private Random random;
    int randomAtama;

    public IntegerNumberGenerator() {
        this.random = new Random();
    }

    @Override
    public int generateNumber() {
        return random.nextInt(100) + 1;
    }
}

public class PrimeNumberChecker implements Runnable {

    private NumberGenerator generator;
    private Lock lock = new ReentrantLock();
    public Condition continueLock = lock.newCondition();

    public PrimeNumberChecker(NumberGenerator generator) {
        this.generator = generator;
    }

    @Override
    public void run() {

        while (!generator.isStopped()) {

            int number = generator.generateNumber();
            System.out.println(Thread.currentThread().getName() + " generated " + number);
            if (check(number)) {
                System.out.println(number + " is prime !");
                generator.stop();
            }
        }
    }

    public static boolean check(int number) {

        boolean result = true;
        for (int i = 2; i <= number / 2; i++) {
            if ((number % i) == 0) {
                result = false;
            }
        }
        return result;
    }
}

public class Driver {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newCachedThreadPool();
        NumberGenerator numberGenerator = new IntegerNumberGenerator();
        for (int i = 0; i < 5; i++) {
            executorService.execute(new PrimeNumberChecker(numberGenerator));
        }
        executorService.shutdown();
    }
}

标签: javamultithreadingconcurrencyparallel-processingsynchronization

解决方案


您可以将检查方法优化为:

public static boolean check(int number) {
    for (int i = 2; i <= number / 2; i++) {
        if ((number % i) == 0) {
            return false;
        }
    }
    return true;
}

一旦你知道这个数字不是素数,你就可以早点返回。

当我找到一个质数时,我必须停止它。如果我在 synchronized while 之前使用它,只会发生一个线程进程。应该发生多个线程操作,但应该在找到素数时停止。

您可以通过向标志添加第一个volatile来实现此目的:isStop

 private volatile boolean isStop = false;

generator.isStopped()然后在确定数字是否为素数的方法中检查(也):

public boolean check(int number) {
    for (int i = 2; i <= number / 2; i++) {
        if (generator.isStopped() || number % i == 0) {
            return false;
        }
    }
    return true;
}

最后,您需要在读取check方法的值时进行同步,因为可能会发生多个线程同时找到素数的情况。因此,将您的代码调整为:

    boolean result = check(number); // All threads to work in parallel
    synchronized (generator) {
        if (result && !generator.isStopped()) {
            System.out.println(number + " is prime !");
            generator.stop();
        }
    }

这里的volatile是不够的,因为多个线程可能会设法进入

if(result && !generator.isStopped())

在其中一个能够实际调用之前generator.stop();。由于完全相同的原因,isStop AtomicBoolean 单独制作变量也无济于事。

关键是语句!generator.isStopped(),并且generator.stop();必须在同一个关键区域内执行,要么使用同步,要么在同一个过程中原子地执行这两个操作。因此,为了AtomicBoolean工作,您必须执行以下操作:

public abstract class NumberGenerator {

    private final AtomicBoolean isStop = new AtomicBoolean(false);

    public abstract int generateNumber();

    public void stop() {
        this.isStop.set(true);
    }

    public boolean isStopped() {
        return isStop.get();
    }

    public boolean getAndSet(){
        return isStop.getAndSet(true);
    }
}

 if (check(number) && !generator.getAndSet()) {
       System.out.println(number + " is prime !");
   }

因为它getAndSet是原子完成的,所以您不会冒让多个线程打印出它们的素数的风险。

我想要做的是使用锁定和同步找到素数。

如果您的意思是只使用一个或另一个(因为您不需要同时使用两者),那么您可以执行以下操作:

    boolean result = check(number);
    synchronized (generator) {
        if (result && !generator.isStopped()) {
            System.out.println(number + " is prime !");
            generator.stop();
        }
    }

即使没有volatile ,这也可以工作。


推荐阅读