有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程在Java多线程中使用BlockingQueue查找素数

我已经用BlockingQueue实现了一个多线程程序来测试一个数字是否为素数

要求是程序将提示用户输入一个数字,然后程序将按升序从2到用户输入的数字打印每个素数

我有3个类:numbernumerirationtask用于初始化阻塞队列包含所有要检查的数字,PrimeRunner用于检查数字是否为素数,PrimeChecker用于主类

数字消费任务。java

package multithread;

import java.util.concurrent.BlockingQueue;

public class NumberEnumerationTask implements Runnable {
    private BlockingQueue<Integer> queue;
    private Integer maximum;
    public static Integer DUMMY = new Integer(0);

    public NumberEnumerationTask(BlockingQueue<Integer> queue, Integer maximum) {
        this.queue = queue;
        this.maximum = maximum;
    }

    @Override
    public void run() {
        try {
           enumerate();
           queue.put(DUMMY);
        } catch (InterruptedException e) {
           e.printStackTrace();
        }
    }

    /**
    * Create a BlockingQueue contain Integer number from 1 to maximum.
    * @throws InterruptedException
    */
    private void enumerate() throws InterruptedException {
        for (int i = 2; i < maximum; i++) {
           queue.put(i);
        }
    }
}

PrimeRunner。java

package multithread;

import java.util.concurrent.BlockingQueue;

public class PrimeRunner implements Runnable {

    private BlockingQueue<Integer> queue;

    public PrimeRunner(BlockingQueue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            boolean done = false;
            while (!done) {
                Integer checkNumber = queue.take();
                if (checkNumber == NumberEnumerationTask.DUMMY) {
                    queue.put(checkNumber);
                    done = true;
                } else {
                    checkPrimeNumber(checkNumber);
                }
            }
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void checkPrimeNumber(Integer number) {
        boolean isPrime = true;
        for (int i = 2; i <= number / 2; i++) {
            if (number % i == 0) {
                isPrime = false;
                queue.remove(number);
                break;
            } 
        }
        if (isPrime == true) {
            System.out.print(number + " ");
            queue.remove(number);
        }
    }
}

PrimeChecker。java

public class PrimeChecker {

    public static void main(String[] args) {
    
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter maximum number to check: ");
        Integer number = sc.nextInt();
    
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(number);
    
        NumberEnumerationTask initialize = new NumberEnumerationTask(queue, number);
        new Thread(initialize).start();
    
        for (int i = 0; i <= number; i++) {
            new Thread(new PrimeRunner(queue)).start();
        }
    
        sc.close();
    }
}

虚拟变量表示完成

当我运行程序时,有时它不是按升序打印的,有时它是按升序打印的

Enter maximum number to check: 100

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Enter maximum number to check: 100

2 3 5 7 11 13 17 19 23 29 31 41 43 47 37 59 61 53 67 71 73 79 83 89 97

有人能告诉我我的代码有什么问题吗?谢谢


共 (2) 个答案

  1. # 1 楼答案

    PrimeChecker中,以下代码是原因:

    for (int i = 0; i <= number; i++) {
        new Thread(new PrimeRunner(queue)).start();
    }
    

    您可以创建多个PrimeRunner实例,并为每个实例创建一个线程,因此可能会发生如下情况:

    1. 线程1中的PrimeRunner取5
    2. 线程2中的PrimeRunner需要7
    3. 线程2中的PrimeRunner打印7。(线程1中的PrimeRunner仍在检查…)
    4. 线程1中的PrimeRunner打印5

    如果你运行一个PrimeRunner,你可以避免这种情况,它会像你预期的那样工作。 如果您仍然想通过synchronized块运行多个PrimeRunner围绕以下部分,并且静态字段为PrimeRunner的对象应该解决这个问题:

    Integer checkNumber = queue.take();
    if (checkNumber == NumberEnumerationTask.DUMMY) {
        queue.put(checkNumber);
        done = true;
    } else {
        checkPrimeNumber(checkNumber);
    }
    
  2. # 2 楼答案

    线程安全是主要问题。在您的代码中,队列在没有任何同步机制的线程之间共享,因此可能会发生数据损坏,从而导致不可预测的结果。如果运行多次,可能会得到不同的结果

    多线程可用于基本检查,以加快主要目标的实现,即通过将大数N拆分为多个部分来实现基本查找,单个线程将处理这些部分,一个线程将聚合结果