无法复制您报告的体验。
在我心目中的调试器中,这似乎是正确的,因为我在代码中看不到任何线程安全错误。
为了自动化进一步测试,我按如下方式更改了您的代码。而不是打电话System.out.println
,我将线程 ID 添加到List
of Long
。我把清单列出来了CopyOnWriteArrayList https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteArrayList.html为了线程安全。我可以通过编程方式检测结果列表的大小是否不正好是 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
直接上课。相反,使用执行者 https://docs.oracle.com/javase/tutorial/essential/concurrency/executors.htmlJava 5 中添加了框架。
这是上面代码的修订版本,重新调整以使用执行器服务。
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() );
}