[英]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.