AtomicInteger线程安全性



我如何才能实现这里的while循环总是精确执行100次。当我执行代码时,在极少数情况下,它会在控制台上打印99或98行,而不是总是打印100行,我对此并不理解。

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
public class Print implements Runnable {
static AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public void run() {
while (atomicInteger.getAndIncrement() < 100)
System.out.println(Thread.currentThread());
}
public static void main(String[] args) throws InterruptedException {
ArrayList<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; i++)
threads.add(new Thread(new Print()));
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
}
}

无法复制您报告的体验。

在我心目中的调试器中,这似乎是正确的,因为我在您的代码中看不到任何线程安全故障。

为了自动化进一步的测试,我对您的代码进行了如下修改。我没有调用System.out.println,而是将线程ID添加到LongList中。为了线程安全,我将该列表列为CopyOnWriteArrayList。我可以通过编程检测结果列表的大小是否不完全是100个元素。

package work.basil.demo;
import java.time.Instant;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
public class Print implements Runnable
{
static AtomicInteger atomicInteger = new AtomicInteger( 0 );
static CopyOnWriteArrayList < Long > list = new CopyOnWriteArrayList <>();
@Override
public void run ( )
{
while ( atomicInteger.getAndIncrement() < 100 )
//System.out.println(Thread.currentThread());
list.add( Thread.currentThread().getId() );
}
public static void main ( String[] args ) throws InterruptedException
{
System.out.println( "INFO - demo starting. " + Instant.now() );
for ( int cycle = 0 ; cycle < 1_000_000 ; cycle++ )
{
ArrayList < Thread > threads = new ArrayList <>();
for ( int i = 0 ; i < 5 ; i++ )
threads.add( new Thread( new Print() ) );
for ( Thread thread : threads )
thread.start();
for ( Thread thread : threads )
thread.join();
//            System.out.println( "list.size() = " + list.size() );
//            if ( list.size() == 100 ) { System.out.println( "DEBUG list.size() = " + ( list.size() ) ); }
if ( list.size() != 100 ) { System.out.println( "DEBUG list.size() = " + ( list.size() ) ); }
}
System.out.println( "INFO - demo done. " + Instant.now() );
}
}

当在Mac mini(2018(3 GHz Intel Core i5上运行时,它有六个实核,没有超线程,32 GB 2667 MHz DDR4,使用IntelliJ中的Java 16。运行cycle到一百万大约需要5分钟。

INFO - demo starting. 2021-06-08T22:11:56.010181Z
INFO - demo done. 2021-06-08T22:16:26.982616Z

ExecutorService

顺便说一句,在现代Java中,我们很少需要直接寻址Thread类。相反,使用添加到Java5中的Executors框架。

这是上面代码的修订版本,重新调整为使用executor服务。

public static void main ( String[] args ) throws InterruptedException
{
System.out.println( "INFO - demo starting. " + Instant.now() );
for ( int cycle = 0 ; cycle < 1_000_000 ; cycle++ )
{
ExecutorService executorService = Executors.newFixedThreadPool( 5 );
int countTasks = 5;
for ( int i = 0 ; i < countTasks ; i++ )
{
executorService.submit( new Print2() );
}
executorService.shutdown();
executorService.awaitTermination( Duration.ofMinutes( 7 ).toSeconds() , TimeUnit.SECONDS );
//            System.out.println( "list.size() = " + list.size() );
//            if ( list.size() == 100 ) { System.out.println( "DEBUG list.size() = " + ( list.size() ) ); }
if ( list.size() != 100 ) { System.out.println( "DEBUG list.size() = " + ( list.size() ) ); }
}
System.out.println( "INFO - demo done. " + Instant.now() );
}
static AtomicInteger atomicInteger = new AtomicInteger(0); change to
AtomicInteger atomicInteger = new AtomicInteger(1);// 0->1 no static

while (atomicInteger.getAndIncrement() < 100) //change to:
while (atomicInteger.getAndIncrement() != 101)//100->101

删除";静态";用于变量atomicInteger。如果您需要精确地获得1…100(而不是0…99(,请将原子值设置为1,并在循环中设置=101我的印刷品https://gyazo.com/6762c78ae44c0b06d05e316768114167

该评论澄清了这个问题:关键是使用静力学。使用信号

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class Print implements Runnable {
static AtomicInteger atomicInteger = new AtomicInteger(1);
private final Semaphore semaphore;
public Print(final Semaphore semaphore) {
this.semaphore = semaphore;
}
@Override
public void run() {
int count = 0;
try {
semaphore.acquire();
while ((count = atomicInteger.getAndIncrement()) != 101) {
System.out.println(
"COUNT::" + count + "::" + Thread.currentThread());
}
atomicInteger.set(1);

} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
semaphore.release();
}
}
public static void main(String[] args) throws InterruptedException {
List<Thread> threads = new ArrayList<>();
Semaphore semaphore = new Semaphore(1);
for (int i = 0; i < 5; i++)
threads.add(new Thread(new Print(semaphore)));
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
}
}

最新更新