我写了最简单的资源来重现问题如下
package concurrency.test;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class Main
{
public static void main(String[] args)
{
new Main().start();
}
private void start()
{
for (int i = 0; i < 20; i++)
{
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new SequencePrinter(), 1, 1, TimeUnit.SECONDS);
}
}
private class SequencePrinter implements Runnable
{
@Override
public void run()
{
System.out.println( IdGenerator.instance().nextId());
}
}
private static class IdGenerator
{
private static IdGenerator instance;
private final AtomicLong idSequence = new AtomicLong( 0 );
private IdGenerator()
{
}
public static IdGenerator instance ()
{
if ( instance == null )
{
instance = new IdGenerator();
}
return instance;
}
synchronized public long nextId ()
{
return idSequence.incrementAndGet();
}
}
}
我的期望:无序的唯一ID
我发现:多个1(任何其他数字是唯一的但不是&#39; 1&#39;)
看起来我还没有理解并发的一些基本概念。你能告诉我我做错了什么吗?
答案 0 :(得分:4)
类instance()
的{{1}}方法不是线程安全的,因此当多个线程调用时,可能会创建此类的多个实例,每个实例都有自己的IdGenerator
成员变量该方法同时进行。
您需要使idSequence
方法具有线程安全性,例如将其设为instance()
。
答案 1 :(得分:0)
同步增量的同步点是什么?下次,始终使用static Type singlenote = new ...
创建单例。
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class SequencePrinter implements Runnable {
public void run() {
System.out.println("produces " + idSequence.incrementAndGet());
}
public static void main(String[] args) {
for (int i = 0; i < 200; i++)
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
new SequencePrinter(), 1, 10, TimeUnit.SECONDS);
}
private static final AtomicLong idSequence = new AtomicLong( 0 );
}
代码变得简单得多,但却被淘汰了。您可能想在getNext中创建实例,这就是为什么要对它进行同步?不要制造大量无用的吸气剂方法。
答案 2 :(得分:0)
这应该做到。 instance
方法中的check-then-act是一种竞争条件,它必须是原子的。
if (instance == null) {
instance = new IdGenerator();
}
第二,idSequence
是atomicLong,因此不需要同步。
private static class IdGenerator
{
private static IdGenerator instance;
private final AtomicLong idSequence = new AtomicLong( 0 );
private static Object lock = new Object();
private IdGenerator()
{
}
public static IdGenerator instance ()
{
synchronized (lock) {
if (instance == null) {
instance = new IdGenerator();
}
}
return instance;
}
public long nextId ()
{
return idSequence.incrementAndGet();
}
}
}