Как мне сделать эту нить безопасной?

#java #multithreading #thread-safety #concurrent.futures

Вопрос:

безопасна ли эта нить? Я продолжаю получать разные результаты каждый раз, когда не уверен, как сделать этот поток безопасным. Моя цель состоит в том, чтобы вычислить количество простых чисел, начиная с 5 -10000, но для этого используется поток для каждого вычисления. Я хотел бы отслеживать общее количество простых чисел. если я выполню приведенный ниже код, то иногда получу 21, а иногда 22.

 import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.io.IOException;

public class Main {
     private static AtomicInteger count =new AtomicInteger(0);
    private static ExecutorService ex = Executors.newFixedThreadPool(100);
   
     public static void main(String []args) throws IOException {
        int x =5;
        while(x < 90){
            final int index =x;
           ex.execute(new Runnable(){
                public void run(){
                    synchronized(count){
                        if(isPrime(index)){
                            count.incrementAndGet();
                        }
                    }
                }
            });
            x  ;
            //new Thread(task).start();
        }
        ex.shutdown();
        System.out.println(count.get()  "this how many numbers are  prime");
     }
     
    public static boolean isPrime(int n)
    {
        // Corner cases
        if (n <= 1)
            return false;
        if (n <= 3)
            return true;
 
        // This is checked so that we can skip
        // middle five numbers in below loop
        if (n % 2 == 0 || n % 3 == 0)
            return false;
 
        for (int i = 5; i * i <= n; i = i   6)
            if (n % i == 0 || n % (i   2) == 0)
                return false;
 
        return true;
    }
}
 

Комментарии:

1. » эта нить Безопасна? Я продолжаю получать разные результаты каждый раз, когда не уверен, как сделать этот поток безопасным». — Если программа сама по себе должна вести себя детерминированно, и вы получаете разные результаты при параллельном выполнении, то, скорее всего, она небезопасна для потоков. — Подсказка: count это не атомарная операция. — Подсказка 2: Взгляните на AtomicInteger

2. @Turing85 я попробовал AtomicInteger с той же проблемой, я обновил сообщение с последними изменениями, нужно ли синхронизировать функцию isPrime?

3. Я никогда не говорил, что это будет единственной проблемой. Пожалуйста, ознакомьтесь с документацией ExecutorServce::shutdown .

4. @Turing85 спасибо за помощь, я думаю, что теперь я ее получил!

Ответ №1:

добавление функции shutdownAndAwaitTermination(ExecutorService ex) устранило проблему, а не просто вызов ex.shutdown(); , я позвонил shutdownAndAwaitTermination(ex);

  public static void shutdownAndAwaitTermination(ExecutorService ex) {
    ex.shutdown(); // Disable new tasks from being submitted
    try {
     // Wait a while for existing tasks to terminate
     if (!ex.awaitTermination(60, TimeUnit.SECONDS)) {
       ex.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!ex.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     ex.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 } 
 

Комментарии:

1. Вы должны удалить первый awaitTermination(...) вызов. Он просто будет спать в течение 60 нескольких секунд, потому что вы не выключили ExecutorService его . Если вы действительно хотите подождать фоновых задач 120 секунд, просто измените значение awaitTermination после shutdownNow() на 120.