프로그래밍에서 “원자”는 무엇을 의미합니까? long이거나 double[JLS, 17.4.7]

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

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

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



답변

예제는 종종 긴 설명보다 명확하기 때문에 예제가 있습니다. 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;


답변

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


답변

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

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

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

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


답변

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

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

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

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


답변

아래 코드에서 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사이에) .


답변

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


답변