使用Java中的BlockingQueue通过多线程查找素数

时间:2016-11-22 03:56:51

标签: java multithreading blockingqueue

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

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

我有3个类: NumberEnumerationTask 用于初始化BlockingQueue包含要检查的所有数字, PrimeRunner 用于检查数字是否为素数, PrimeChecker 为主要班级。

NumberEnumerationTask.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();
    }
}

DUMMY 变量表示完成。

当我运行该程序时,有时它不按升序打印,有时它会打印。

  

输入要检查的最大数量: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

     

输入要检查的最大数量: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 个答案:

答案 0 :(得分: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。
  5. 如果你运行一个PrimeRunner,你可以避免这种情况,它可以按预期工作。 如果您仍希望在PrimeRunner块周围运行多个synchronized,并且PrimeRunner的静态字段中的对象可以解决问题:

    Integer checkNumber = queue.take();
    if (checkNumber == NumberEnumerationTask.DUMMY) {
        queue.put(checkNumber);
        done = true;
    } else {
        checkPrimeNumber(checkNumber);
    }
    

答案 1 :(得分:-1)

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

多线程可以用于质量检查以加速主要目标,即可以通过将大数N分成多个部分来实现的主要发现,并且单个线程将在这些部分上工作并且一个线程来聚合结果。