2014-07-08 56 views
1

我已經寫了簡單的源來重現問題如下意外行爲(爪哇)

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')

它看起來像我還沒有理解一些併發的基本概念。你能告訴我我做錯了什麼嗎?

回答

4

IdGenerator類的instance()方法不是線程安全的,這個類的多個實例可以被創建,每個都有自己的idSequence成員變量,當多個線程同時調用該方法。

您需要使instance()方法線程安全,例如將其設置爲​​。

+0

謝謝,這很容易:)我感到羞愧 – skuzuc

+0

的確,我認爲他想把關鍵字'synchronized'作爲getInstance的修飾符,但是把它用於'inc',這沒有任何意義。 – Val

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中創建實例,這就是爲什麼你要同步它?不要創建大量無用的getter方法。