유효 Java 책에는 다음과 같이 명시되어 있습니다.
언어 사양은 변수가 유형
long
이거나double
[JLS, 17.4.7] 이 아니면 변수를 읽거나 쓰는 것이 원자 성임을 보증합니다.
"원자"는 Java 프로그래밍 또는 일반적인 프로그래밍의 맥락에서 무엇을 의미합니까?
volatile long
하거나 volatile double
원자로 만듭니다.
유효 Java 책에는 다음과 같이 명시되어 있습니다.
언어 사양은 변수가 유형
long
이거나double
[JLS, 17.4.7] 이 아니면 변수를 읽거나 쓰는 것이 원자 성임을 보증합니다.
"원자"는 Java 프로그래밍 또는 일반적인 프로그래밍의 맥락에서 무엇을 의미합니까?
volatile long
하거나 volatile double
원자로 만듭니다.
답변:
예제는 종종 긴 설명보다 명확하기 때문에 예제가 있습니다. 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 = 1234567890L
A의 원자 보장되지 않습니다 long
(JVM이 두 작업의 첫 번째 32 비트와 마지막 32 비트를 쓸 수 및 스레드 관찰 할 수 i
사이에) .