2013-02-06 4 views
0
class ABC{ 
private static Random random = new Random(); 
private static AtomicLong uniqueLongId = new AtomicLong(System.currentTimeMillis()); 

public static long getUniqueLongId(){ 

      long id = uniqueLongId.incrementAndGet(); 
      long uniqueID = Math.abs(random.nextLong()) + id; 
      return uniqueID; 

      //the above code we can write in one line 
    //return Math.abs(random.nextLong())+uniqueLongId.incrementAndGet(); 

} 
} 

위의 getUniqueLongId() 메소드는 멀티 스레드 환경에서 고유 ID를 제공 할 것입니다. 내 관심사는 다음과 같습니다. uniqueLongId가 원자임을 알고, incrementAndGet() 호출은 스레드 안전 호출이지만 코드의 다른 부분은 동기화되지 않는다고 가정합니다. 이것은 getUniqueLongId() 메서드 자체가 스레드로부터 안전하지 않다는 것을 의미하지 않을까요? 따라서 고유 한 ID를 반드시 반환하지 않을 수도 있습니다.고유 ID를 생성하기 위해 원자를 사용하기

설명해주십시오 ..

+3

를 스레드 안전하지 않은 것, 당신의 ID는 고유하지 않습니다. id = 1이고 무작위로 3 => uniqueId = 4/다음 실행 : id = 2이고 random은 2 => uniqueId = 4를 다시 반환한다고 가정하십시오. – assylias

+0

예. 동의합니다. 그러나 나는 일어난 일의 기회가 아직 멀고 내 앱에 tats gud enuf라고 생각한다. 이 메소드를 사용하여 같은 id를 생성하는 abt 2 개의 즉각적인 스레드 즉,이 메소드가 스레드 안전인지 여부에 대해 더 관심이 있습니다! – anzaan

답변

2

Java 7 docs 쓰기 : java.util.Random

인스턴스는 스레드입니다. 그러나 스레드간에 동일한 java.util.Random 인스턴스를 동시에 사용하면 경합이 발생하여 성능이 저하 될 수 있습니다. 대신 멀티 스레드 디자인에서 ThreadLocalRandom을 사용하십시오.

코드가 Java 7에서 스레드 안전합니다. 모든 작업은 스레드 안전 메소드 호출 또는 로컬 변수에서만 작동합니다. 그리고 당신은 원 자성을 필요로하지 않습니다. 즉, 다음 시퀀스 번호가 다음 임의의 숫자와 쌍을 이루도록 요구하지 않습니다.

(귀하의 의견에 따라) API 문서의 이전 버전에는 그러한 보장이 없으므로 이론적으로는 스레드가 안전하지 않을 수 있습니다. 그러나 Sun JDK 1.4.2.19 (내가 가지고있는 가장 오래된 버전)의 src.zip을 보면 코드는 이미 원자 변수를 사용하므로 실제로는 thread-safe 동작을 제공합니다.

즉, 코드에는 여러 가지 문제가 있습니다. 위에서 인용 한 것처럼 성능이 좋지 않을 수 있습니다. assylias already wrote in a comment으로,이 방법은 단순한 Random 것보다 더 많은 고유 번호를 부여하지 않습니다. 또한 Math.abs(Long.MIN_VALUE)은 여전히 ​​음수가 될 것이며, 양수 난수 + id는 오버플로 및 랩 어라운드를 일으킬 수 있습니다. 따라서 양수가 필요하면 더 많은주의를 기울여야합니다. 최종 uniqueID &= 0x7fffffffffffffffL은 도중의 Math.abs보다 더 적합 할 수 있습니다.

+0

올바른 설명을 위해 +1 –

+0

위의 Jdk1.7에 ThreadDeclash가 추가되었습니다. 내가 jdk1.6을 사용하고 있었고, 내가 그것을 그리워했는지에 관해 궁금하게 생각하고 있었다!! thnx는 Math.abs (Long.MIN_VALUE)가 음수임을 나타냅니다. u "모든 작업은 스레드 안전 메서드 호출 또는 로컬 변수에서만 작동 중입니다." Math.abs(), 스레드 안전성을 보장하는 부과 및 추가 연산이 있습니다. 또한 작업에 로컬 변수를 사용하면 스레드 안전성이 어떻게됩니까? 내가 코드 블록/메소드를 동기화하면 다른 스레드가이를 입력 할 수 없으므로 스레드 세이프가됩니다. 그게 여기에 있니? – anzaan

+0

@anzaan : 작업이 일부 공유 상태에 동시에 액세스 할 때 비 threadsafe가됩니다. 일부 경우에는 일관성이 없습니다. 'Math.abs()'는 공유 상태를 사용하지 않으므로 문서의 명시 적으로 그렇게 말하지 않아도 스레드로부터 안전합니다. 로컬 변수는 공유되지 않으므로 이들에 대한 연산도 스레드 안전성이 있습니다. 'synchronized' 블록에 의해 제공되는 상호 배제는 [thread safety] (http://en.wikipedia.org/wiki/Thread_safety)를 달성하는 몇 가지 방법 중 하나 일뿐입니다. jdk1.6의'Random'에 대한 안전 보장이 없다면'random'에 동기화를 원할 수 있습니다. – MvG

1

실제로 스레드로부터 안전합니다. MvG의 대답이 이유를 설명합니다.

@assylias에서 언급했듯이 단일 스레드 환경에서는 고유 ID를 생성하지 않을 수도 있습니다.

MongoDB의 ObjectId 생성 메커니즘을 연구하는 데 가치가 있습니다.

고유성을 보장하기 위해 도입 된 매개 변수는 네 가지가 있습니다. 말했다되고 그건

a 4-byte timestamp, 
a 3-byte machine identifier, 
a 2-byte process id, and 
a 3-byte counter. 

는이 목적을 위해 선반을 사용할 수 있습니다 JDK에 UUID 클래스가있다.

caveat 그것도 하나의 스레드에서 JDK 7까지

+0

당신 말이 맞아요. 나는 무작위가 스레드로부터 안전하다는 것에 대해 의구심을 품었다. 답변 정정. –