java—当其中一个线程找到素数时如何停止线程

9rygscc1  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(392)

当一个素数被发现时,我必须阻止它。当我在 while ,只会发生一个线程进程。但是,应该发生多线程操作,但是当找到prime时,所有操作都应该停止。
初始值 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();

    }

}
xcitsw88

xcitsw881#

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

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(); 必须在相同的关键区域内执行,要么使用同步的,要么在同一个go中原子地执行两个操作。因此,对于 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();
        }
    }

即使没有挥发性物质,这也能起作用。

gmxoilav

gmxoilav2#

线程本身应该知道抽象类中的“何时应该停止”逻辑,而不是该逻辑。因此,我将在runnable类中添加一个atomicboolean作为标志,并添加一个stop()方法来处理它。然后run方法将寻找每当这个布尔值改变时停止的atomicboolean。
像这样:

public class PrimeNumberChecker implements Runnable {
    //Flag to control the running
    private final AtomicBoolean isRunning = new AtomicBoolean(false);

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

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

    @Override
    public void run() {     
       isRunning.set(true);
       while (isRunning.get()) {        
            int number = generator.generateNumber();
            System.out.println(Thread.currentThread().getName() + " generated " + number);
            if (check(number)) {
                System.out.println(number + " is prime !");
                generator.stop();
            }

        }

    }       

    // So you can stop it from the outside
    public void stop() {
        isRunning.set(false);
    }

    public static boolean check(int number) {

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

相关问题