[英]Unexpected behavior in concurrency (Java)
我已经编写了最简单的源代码来重现问题,如下所示
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(任何其他数字都是唯一的,但不是“1”)
看来我还没有理解并发的一些基本概念。 你能告诉我我做错了什么吗?
您的类IdGenerator
的instance()
方法不是线程安全的,因此当多个线程同时调用该方法时,可能会创建此类的多个实例,每个实例都有自己的idSequence
成员变量。
您需要使instance()
方法成为线程安全的,例如通过使其成为synchronized
。
同步同步增量有什么意义? 下一次,总是使用static Type singlenote = new ...
来创建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 中创建实例,这就是您对其进行同步的原因? 不要创建大量无用的 getter 方法。
这应该这样做。 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();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.