프로그래밍에서 "원자"는 무엇을 의미합니까?


276

유효 Java 책에는 다음과 같이 명시되어 있습니다.

언어 사양은 변수가 유형 long이거나 double[JLS, 17.4.7] 이 아니면 변수를 읽거나 쓰는 것이 원자 성임을 보증합니다.

"원자"는 Java 프로그래밍 또는 일반적인 프로그래밍의 맥락에서 무엇을 의미합니까?


24
한 번에 하나의 작업.
Subhrajyoti Majumder

1
변수는 한 번에 하나의 작업 만 수행 할 수 있습니다.
kaysush


1
철학 질문이 codereview.stackexchange.com
Phlip

일부 변수에는 기본적으로 원자 읽기 및 쓰기가 없으므로 원자를 읽기 또는 쓰기로 선언 volatile long하거나 volatile double원자로 만듭니다.
H2ONaCl

답변:


372

예제는 종종 긴 설명보다 명확하기 때문에 예제가 있습니다. foo유형의 변수 라고 가정 합니다 long. 다음 작업은 원 자성 작업이 아닙니다.

foo = 65465498L;

실제로 변수는 두 개의 별도 연산을 사용하여 작성됩니다. 하나는 첫 번째 32 비트를 기록하고 다른 하나는 마지막 32 비트를 기록합니다. 이는 다른 스레드가의 값을 읽고 foo중간 상태를 볼 수 있음을 의미합니다 .

작업을 원 자성으로 만드는 것은 다른 스레드에서 작업이 단일 원자 (예 : 부분적으로 분할 할 수 없음) 작업으로 표시되도록하기 위해 동기화 메커니즘을 사용하는 것으로 구성됩니다. 즉, 작업이 원자화되면 다른 스레드 foo는 할당 전 또는 할당 후의 값을 볼 수 있습니다 . 그러나 결코 중간 가치가 아닙니다.

이를 수행하는 간단한 방법은 변수를 휘발성 으로 만드는 것입니다 .

private volatile long foo;

또는 변수에 대한 모든 액세스를 동기화하려면

public synchronized void setFoo(long value) {
    this.foo = value;
}

public synchronized long getFoo() {
    return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized

또는 다음과 같이 바꾸십시오 AtomicLong.

private AtomicLong foo;

75
따라서 이것은 32 비트 시스템에서 실행되고 있다고 가정합니다. 64 비트 시스템이라면? foo = 65465498L 일 것임; 그러면 원자가 되나요?
Harke

46
@Harke 64 비트 Java를 실행중인 경우 가능합니다.
Jeroen

4
이것은 C # 및 .NET에도 적용됩니까? 그렇다면 foo가 원자적인 behavir를 얻으려면 CLR이 64 비트 여야합니까?
Fabiano

5
@Fabiano Java와 같은 동기화 된 키워드가 없기 때문에 .NET에서 적용하는 방법이 여기에 있습니다. stackoverflow.com/questions/541194/…
머핀 맨

2
그런 다음 스레드 A가 긴 값을 할당 한 다음 스레드 B가이를 읽는 방법의 절반을 가정합니다. 작업 A가 원자 적이면 스레드 B가 완료 될 때까지 기다 립니까? 이것은 원자 연산이 암시 적 스레드 안전성을 제공한다는 것을 의미합니까?
Teoman shipahi

60

"원자 작업"은 다른 모든 스레드의 관점에서 순간적으로 나타나는 작업을 의미합니다. 보증이 적용될 때 부분적으로 완료된 작업에 대해 걱정할 필요가 없습니다.


25

"시스템의 나머지 부분에 즉시 나타납니다" 는 컴퓨팅 프로세스에서 선형화 범주에 속합니다 . 링크 된 기사를 더 인용하려면 :

원자 성은 동시 프로세스와의 격리를 보장합니다. 또한 원자 작업은 일반적으로 성공 또는 실패 정의를 갖습니다. 시스템 상태를 성공적으로 변경하거나 명백한 영향을 미치지 않습니다.

예를 들어, 데이터베이스 시스템의 맥락에서 '원자 커밋'을 가질 수 있습니다. 즉, 업데이트의 변경 세트를 관계형 데이터베이스에 푸시 할 수 있으며 이러한 변경 사항은 모두 제출되거나 전혀 제출되지 않습니다. 이러한 방식으로 데이터가 손상되지 않고 결과적으로 잠금 및 / 또는 큐가 실패하는 경우 다음 작업은 다른 쓰기 또는 읽기이지만 사실 이후 에만 수행됩니다 . 변수와 스레딩의 맥락에서 이것은 메모리에 적용되는 것과 거의 동일합니다.

귀하의 인용문은 이것이 모든 경우에 이것이 예상되는 행동 일 필요는 없다는 것을 강조 합니다.


15

Atomic vs. Atomic Operations 게시물 이 매우 유용 하다는 것을 알았 습니다.

"공유 스레드에서 작동하는 작업은 다른 스레드에 비해 단일 단계에서 완료되면 원 자성입니다.

원자 저장소가 공유 메모리에서 수행되면 다른 스레드는 수정 반 완료를 관찰 할 수 없습니다.

원자 변수가 공유 변수에 대해 수행 될 때 단일 시점에 나타난 전체 값을 읽습니다. "


14

아래 코드에서 m1 및 m2 메소드를 실행하는 스레드가 여러 개인 경우 :

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

모든 스레드 호출 m2이 0 또는 5를 읽도록 보장합니다 .

반면 에이 코드 i를 사용하면 길다.

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

스레드 호출이 m2명령문이 때문에 0, 1234567890L, 또는 다른 임의의 값을 읽을 수 i = 1234567890LA의 원자 보장되지 않습니다 long(JVM이 두 작업의 첫 번째 32 비트와 마지막 32 비트를 쓸 수 및 스레드 관찰 할 수 i사이에) .


"int"가 아닌 "long"이 문제를 일으키는 이유는 무엇입니까? 여기를 참조하십시오 geekswithblogs.net/BlackRabbitCoder/archive/2012/08/09/…
onmyway133

1
@entropy long 및 double 할당은 Java에서 원 자성으로 보장되지 않습니다. 따라서 할당 후 비트의 절반 만 업데이트 된 긴 부분을 읽을 수 있습니다.
assylias

0

Java에서 long 및 double을 제외한 모든 유형의 필드를 읽고 쓰는 경우 원자 적으로 발생하며 필드가 volatile 수정 자로 선언되면 long 및 double도 원자 적으로 읽고 쓸 수 있습니다. 즉, 우리는 그곳에 있었던 일이나 일어난 일을 100 % 얻거나 변수에 중간 결과가있을 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.