#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.