Java에서 휘발성과 동기화의 차이
를 '하다'로 과 '하다'로 선언하는 것의 .volatile.synchronized(this)자바 ★★★★★★★★★★★★★★★?
이 기사 http://www.javamex.com/tutorials/synchronization_volatile.shtml에 따르면 할 말이 많고 많은 차이점이 있지만 몇 가지 유사점도 있다.
저는 특히 이 정보에 관심이 있습니다.
...
- 휘발성 변수에 대한 접근은 차단할 가능성이 없습니다.단순한 읽기 또는 쓰기 작업만 수행하므로 동기화된 블록과는 달리 잠금을 유지할 수 없습니다.
- 휘발성 변수에 액세스하는 것은 결코 잠금을 보유하지 않기 때문에 (업데이트를 놓칠 준비가 되어 있지 않은 한) 원자적인 조작으로서 read-update-write를 원하는 경우에는 적합하지 않습니다.
read-update-write는 무엇을 의미합니까?쓰기도 업데이트 아닌가요?아니면 단순히 읽기에 따라 달라지는 쓰기인가요?
변수 가 더 요?volatile하는 것이 아니라synchronized블록? 용하하 것? ?? ?? ??? ? ?? ??volatile예를 , 변수라고 하는 이 있습니다.render키 누르기 이벤트에 의해 설정되는 렌더링 루프를 통해 읽힙니다.
나사산 안전에는 두 가지 측면이 있다는 것을 이해하는 것이 중요합니다.
- 실행 제어 및
- 메모리 가시성
첫 번째는 코드가 실행되는 시기(명령어를 실행하는 순서 포함)와 동시에 실행될 수 있는지 여부를 제어하는 것과 관련이 있으며, 두 번째는 수행된 작업의 메모리 효과가 다른 스레드에 표시될 때 관련됩니다.각 CPU와 메인 메모리 사이에는 몇 가지 수준의 캐시가 있기 때문에 다른 CPU 또는 코어로 실행되는 스레드는 메인 메모리의 프라이빗 복사본을 취득하여 작업할 수 있기 때문에 언제든지 다른 "메모리"를 인식할 수 있습니다.
「」를 사용합니다.synchronized는 다른 스레드가 같은 오브젝트의 모니터(또는 잠금)를 취득하는 것을 방지하고, 그 결과 같은 오브젝트의 동기화에 의해 보호되는 모든 코드블록이 동시에 실행되지 않도록 합니다.동기화는 또, 「hapens-before」메모리 장벽이 생기기 때문에, 일부 스레드가 잠금을 해제하는 시점까지 행해진 모든 것이, 그 후에 같은 잠금을 취득하기 전에 행해진 것으로 다른 스레드에 보여지도록 메모리 가시성의 제약이 생깁니다.현재의 하드웨어에서는, 통상, 모니터의 취득시에 CPU 캐시가 플러시 해, 릴리스시에 메인 메모리에 써집니다.이러한 캐시는 (상대적으로) 비쌉니다.
「」를 사용합니다.volatile한편, 는 휘발성 변수에 대한 모든 액세스(읽기 또는 쓰기)를 메인메모리에 강제적으로 실행함으로써 실질적으로 휘발성 변수를 CPU 캐시에서 제외합니다.이는 변수의 가시성이 올바르고 액세스 순서가 중요하지 않은 일부 작업에 유용합니다.「」를 사용합니다.volatile도 long ★★★★★★★★★★★★★★★★★」double액세스에 원자성을 필요로 합니다.일부(일부) 하드웨어에서는 잠금을 필요로 하지만 최신 64비트하드웨어에서는 그렇지 않습니다.Java 5+용 새로운 (JSR-133) 메모리 모델에서는 휘발성의 의미가 메모리 가시성 및 명령 순서와 관련하여 동기화된 것과 거의 같은 정도로 강화되었습니다(http://www.cs.umd.edu/users/pugh/java/memoryModel/jsr-133-faq.html#volatile) 참조).가시성을 위해 휘발성 필드에 대한 각 액세스는 절반의 동기화처럼 작동합니다.
새로운 메모리 모델에서는 휘발성 변수를 서로 정렬할 수 없습니다.차이점은 이제 더 이상 이들 주변에서 일반 필드 액세스를 재정렬하는 것이 쉽지 않다는 것입니다.휘발성 필드에 쓰는 것은 모니터릴리즈와 메모리 효과가 같고 휘발성 필드에서 읽는 것은 모니터 취득과 메모리 효과가 동일합니다. 여부에 다른 액세스에 변경에 보다 에 스레드에 휘발성입니다.
A필드 "에 쓸 때f에 비치다B쓰여 때f.
따라서 (현재 JMM에서) 두 가지 형태의 메모리 장벽은 컴파일러 또는 런타임에 의해 장벽을 넘어 명령의 순서를 변경할 수 없도록 하는 명령어 순서 변경 장벽을 일으킵니다.이전 JMM에서는 휘발성 때문에 재주문이 방해되지 않았습니다.메모리 장벽과는 별도로 부과되는 유일한 제한은 특정 스레드에 대해 명령이 소스에 표시되는 순서대로 정확히 실행되었을 때와 같은 코드의 순효과는 같기 때문입니다.
휘발성의 한 가지 용도는 공유되지만 불변의 객체가 즉시 재생성되는 것입니다.다른 많은 스레드는 실행 사이클의 특정 시점에서 객체를 참조합니다.다른 스레드는 재생성된 오브젝트가 퍼블리시된 후 사용을 시작해야 하지만 전체 동기화 및 어텐던트 경합과 캐시 플러싱에 따른 추가 오버헤드는 필요하지 않습니다.
// Declaration
public class SharedLocation {
static public SomeObject someObject=new SomeObject(); // default object
}
// Publishing code
// Note: do not simply use SharedLocation.someObject.xxx(), since although
// someObject will be internally consistent for xxx(), a subsequent
// call to yyy() might be inconsistent with xxx() if the object was
// replaced in between calls.
SharedLocation.someObject=new SomeObject(...); // new object is published
// Using code
private String getError() {
SomeObject myCopy=SharedLocation.someObject; // gets current copy
...
int cod=myCopy.getErrorCode();
String txt=myCopy.getErrorText();
return (cod+" - "+txt);
}
// And so on, with myCopy always in a consistent state within and across calls
// Eventually we will return to the code that gets the current SomeObject.
특히 읽기-업데이트-쓰기 질문에 대한 답변입니다.다음과 같은 안전하지 않은 코드를 고려하십시오.
public void updateCounter() {
if(counter==1000) { counter=0; }
else { counter++; }
}
여기서 update Counter() 메서드가 동기화되지 않은 상태에서 두 개의 스레드가 동시에 입력될 수 있습니다.발생할 수 있는 여러 가지 순열 중 하나는 스레드-1이 카운터==1000에 대해 테스트를 수행하고 그것이 참임을 확인한 후 일시 중단된다는 것입니다.그런 다음 스레드 2도 같은 테스트를 수행하고 true로 인식되어 일시 중단됩니다.다음으로 스레드 1이 재개되어 카운터가0 으로 설정됩니다.그 후 스레드2가 재개되어 스레드1로부터의 갱신을 놓쳤기 때문에 다시 카운터가0 으로 설정됩니다.이는 앞서 설명한 바와 같이 스레드 전환이 발생하지 않더라도 발생할 수 있습니다.단, 단순히 2개의 다른 CPU 코어에 2개의 다른 캐시된 카운터 복사본이 존재하고 각각 다른 코어로 스레드가 실행되었기 때문입니다.이 경우 한 스레드는 하나의 값으로 카운터를 가질 수 있고 다른 스레드는 캐시 때문에 완전히 다른 값으로 카운터를 가질 수 있습니다.
이 예에서 중요한 것은 가변 카운터가 메인 메모리에서 캐시로 읽혀지고 캐시에서 업데이트되며 메모리 장벽이 발생하거나 캐시 메모리가 다른 용도로 필요할 때 중간 지점에서 메인 메모리에 다시 기록된다는 것입니다.카운터 만들기volatile 코드의인 "의 세트"인입니다.read+increment+write 를 들어 과 같은 것.
MOV EAX,counter
INC EAX
MOV counter,EAX
휘발성 변수는 완전히 형성된 객체에 대한 참조가 읽기 또는 쓰기(일반적으로 한 지점에서만 작성됨)되는 예와 같이 실행되는 모든 연산이 "원자"일 때만 유용합니다.다른 예로는 Copy-on-Write 목록을 지원하는 휘발성 어레이 참조를 들 수 있습니다.단, 어레이가 먼저 참조의 로컬 복사본을 가져와 읽기만 하면 됩니다.
volatile은 필드 수식자이며 synchronized는 코드 블록 및 메서드를 변경합니다.이 때문에, 다음의 2개의 키워드를 사용하고, 심플한 액세스의 3개의 변형을 지정할 수 있습니다.
int i1; int geti1() {return i1;} volatile int i2; int geti2() {return i2;} int i3; synchronized int geti3() {return i3;}
geti1()는 현재 되어 있는 합니다.i1현재 스레드에 있습니다.스레드에는 변수의 로컬 복사본이 있을 수 있으며 데이터는 다른 스레드에 저장된 데이터와 같을 필요가 없습니다.다른 되었을 수 .i1그러나 현재 스레드의 값이 업데이트된 값과 다를 수 있습니다.사실 Java는 "메인" 메모리라는 개념을 가지고 있으며, 이것이 변수의 현재 "올바른" 값을 유지하는 메모리입니다.스레드는 변수에 대한 자체 데이터 복사본을 가질 수 있으며 스레드 복사본은 "기본" 메모리와 다를 수 있습니다.따라서 실제로 "메인" 메모리의 값은 다음과 같습니다.i1thread1의 경우 값은 2입니다.i1thread2의 경우 값이 3이 됩니다.i1thread1과 thread2가 둘 다 i1을 업데이트 했지만 업데이트 값이 아직 "메인" 메모리 또는 다른 스레드에 전파되지 않은 경우.반,는
geti2()하게 값을 구하다i2" 츠요시휘발성 변수는 현재 "메인" 메모리에 저장된 값과 다른 변수의 로컬 복사본을 가질 수 없습니다.실질적으로 volatile로 선언된 변수는 모든 스레드에 걸쳐 데이터를 동기화해야 합니다.따라서 스레드 내의 변수에 액세스하거나 갱신할 때마다 다른 모든 스레드는 즉시 동일한 값을 볼 수 있습니다.일반적으로 휘발성 변수는 "일반" 변수보다 액세스 및 업데이트 오버헤드가 높습니다.일반적으로 스레드는 효율성을 높이기 위해 자체 데이터 복사본을 가질 수 있습니다.volitile과 synchronized에는 두 가지 차이가 있습니다.
먼저 동기화된 모니터는 한 번에 하나의 스레드만 강제로 코드 블록을 실행할 수 있는 잠금을 취득하고 해제합니다.동기화하는 것은 잘 알려진 측면입니다.그러나 동기화는 메모리도 동기화합니다.실제로 동기화된 것은 스레드 메모리 전체를 "메인" 메모리와 동기화합니다. 실행 중
geti3()는 다음과 합니다.
- 스레드는 오브젝트 this의 모니터 잠금을 취득합니다.
- 스레드 메모리는 모든 변수를 플러시합니다. 즉, 모든 변수를 "메인" 메모리에서 효과적으로 읽습니다.
- 코드 블록이 실행됩니다(이 경우 반환 값을 "주" 메모리에서 방금 재설정되었을 수 있는 i3의 현재 값으로 설정합니다).
- (변수에 대한 변경은 보통 "메인" 메모리에 쓰이지만 geti3()의 경우 변경되지 않습니다.)
- 스레드는 이 오브젝트에 대한 모니터 잠금을 해제합니다.
따라서 volatile이 스레드메모리와 "메인"메모리 간에 하나의 변수 값만 동기화하는 경우 동기화된 메모리에서는 스레드메모리와 "메인"메모리 간의 모든 변수 값이 동기화되고 모니터가 잠기거나 해제되어 부팅됩니다.명확하게 동기화되면 휘발성보다 오버헤드가 더 클 수 있습니다.
http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html
멀티스레딩에는 주로 3가지 문제가 있습니다.
레이스 조건
캐시/오래된 메모리
컴파일러 및 CPU 최적화
volatile3은 풀 수 은 풀 수 .synchronized1,, 할 수 syslog locks는 1, 2, 3을 해결합니다.
상세:
- 다음 스레드 안전하지 않은 코드를 고려하십시오.
x++;
하나의 조작처럼 보이지만 실제로는 3가지입니다.메모리에서 x의 현재 값을 읽고 1을 더하고 메모리에 저장합니다.동시에 실행하려고 하는 스레드가 거의 없는 경우 작업 결과는 정의되지 않습니다. If 한다면x원래 1, 2개의 스레드가 코드를 작동시킨 후 2가 될 수도 있고 3이 될 수도 있습니다.어느 스레드가 어떤 작업을 완료했느냐에 따라 제어가 다른 스레드로 넘어갑니다.이것은 경주 조건의 한 형태이다.
「」를 사용합니다.synchronized코드 블록은 원자적으로 만듭니다. 즉, 3개의 연산이 동시에 발생하는 것처럼 하며 중간에 다른 스레드가 들어와 간섭할 수 없습니다.그래서 만약에x was 1, and 2 threads try to preform 1, 2개의 스레드가 프리폼을 시도합니다.x++결국 3이 된다는 것을 알고 있습니다.그래서 레이스 컨디션 문제를 해결해 준다.
synchronized (this) {
x++; // no problem now
}
킹 표시x as ~하듯이volatile does not make 만들 수 없다x++;원자, 이 문제를 해결하지 않습니다.이 문제는 해결되지 않습니다.
- 또한 스레드에는 고유한 컨텍스트가 있습니다. 즉, 메인 메모리에서 값을 캐시할 수 있습니다.즉, 일부 스레드에 변수의 복사본이 있을 수 있지만 변수의 새 상태를 다른 스레드 간에 공유하지 않고 작업 복사본에서 작동합니다.
로 「」라고 하는 것을 해 주세요.x = 10; 조금 리고른른른, 른른른른른른른른른.x = 20;의 of 의 값 x다른 스레드가 새 값을 작업 메모리에 저장했지만 메인 메모리에 복사하지 않았기 때문에 첫 번째 스레드에 표시되지 않을 수 있습니다.또는 메인 메모리에 복사했지만 첫 번째 스레드는 작업 복사본을 업데이트하지 않았습니다.서 첫 스레드가 체크했을 if (x == 20)은 '하다, 하다' 입니다.false.
를 " "로 마킹"volatile는 기본적으로 모든 스레드에 메인메모리에서만 읽기 및 쓰기 조작을 실행하도록 지시합니다. synchronized는 모든 스레드가 블록에 들어갈 때 메인메모리에서 값을 갱신하고 블록을 나갈 때 결과를 메인메모리로 되돌리도록 지시합니다.
데이터 레이스와는 달리 오래된 메모리는 메인 메모리에 플러시가 발생하기 때문에 생산(재작성)이 쉽지 않습니다.
- 컴파일러와 CPU는 (스레드 간의 동기 형식을 사용하지 않고) 모든 코드를 단일 스레드로 처리할 수 있습니다.즉, 멀티스레딩 측면에서는 매우 의미 있는 코드를 볼 수 있으며, 하나의 스레드처럼 취급할 수 있으며, 그다지 의미 있는 것은 아닙니다.따라서 이 코드가 여러 스레드에서 작동하도록 설계되었는지 모를 경우 코드를 보고 최적화를 위해 코드를 재정렬하거나 일부를 완전히 제거할 수 있습니다.
다음 코드를 고려합니다.
boolean b = false;
int x = 10;
void threadA() {
x = 20;
b = true;
}
void threadB() {
if (b) {
System.out.println(x);
}
}
20개밖에 할 수 할 수 할 수 ).b사실, 사 to), true)b is set to true only after 다음 시간 후에만 true로 설정됩니다.x20으로 설정되어 있지만 컴파일러/CPU는 스레드 A를 주문하도록 결정할 수 있습니다.는 20 으로 설정되어 있습니다만, 컴파일러/CPU 는 threadA 의 순서를 변경할 가능성이 있습니다.이 경우 threadB 는 10 을 인쇄할 수도 있습니다.킹 표시b as ~하듯이volatile주문 부서 부탁드립니다.는, 재주문(또는 경우에 따라서는 폐기)을 하지 않게 합니다.즉, 스레드B는 20개만 인쇄할 수 있습니다(또는 전혀 인쇄할 수 없습니다).메서드를 동기화된 것으로 표시해도 같은 결과를 얻을 수 있습니다. 변수를 " "로 .volatile에서는 순서가 변경되지 않도록 할 뿐이지만, 그 전/후의 모든 것은 순서를 변경할 수 있기 때문에, 동기가 보다 적합한 시나리오가 있습니다.
Java 5 New Memory Model 이전에는 휘발성으로는 이 문제가 해결되지 않았습니다.
synchronized섹션의 을 한 하고 있는지 합니다.그러면 하나의 스레드가 중요한 섹션의 잠금을 소유하게 됩니다.만 들어갈 수 .synchronized차단. 다른 스레드가 이 중요한 섹션에 액세스하려고 할 경우 현재 소유자가 잠금을 해제할 때까지 기다려야 합니다.
volatile는 모든 스레드가 변수의 최신 값을 메인메모리로부터 취득하도록 강제하는 가변 액세스 수식자입니다.세세 no no no no no no no no no에 액세스하기 위해 .volatile 수 .모든 스레드는 동시에 휘발성 변수 값에 액세스할 수 있습니다.
variable을 예: " " " " " " 。Date★★★★★★ 。
를 변수로 .volatile이 변수에 액세스하는 모든 스레드는 항상 메인 메모리에서 최신 데이터를 가져와 모든 스레드에 실제(실제) 날짜 값이 표시되도록 합니다.동일한 변수에 대해 다른 시간을 표시하는 다른 스레드는 필요하지 않습니다.모든 스레드에 올바른 날짜 값이 표시됩니다.
자세한 내용은 이 기사를 참조해 주십시오.volatile★★★★★★ 。
Dol 의 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.read-write-update query
기타 문의에 대하여
변수를 동기화된 방법으로 액세스하는 것보다 휘발성을 선언하는 것이 적절한 시기는 언제입니까?
쓰셔야 돼요.volatile날짜 변수에 대해 설명한 예시와 같이 모든 스레드가 변수의 실제 값을 실시간으로 얻어야 한다고 생각하는 경우.
입력에 의존하는 변수에는 휘발성을 사용하는 것이 좋은 생각입니까?
답변은 첫 번째 쿼리와 동일합니다.
자세한 내용은 이 문서를 참조하십시오.
언급URL : https://stackoverflow.com/questions/3519664/difference-between-volatile-and-synchronized-in-java
'programing' 카테고리의 다른 글
| Python 대화형 세션을 저장하는 방법 (0) | 2023.01.04 |
|---|---|
| set Timeout 또는 set Interval? (0) | 2023.01.04 |
| Maria에서 느린 업데이트, 삭제 및 쿼리 삽입DB (0) | 2023.01.04 |
| jQuery를 사용하여 양식 입력 필드를 가져오시겠습니까? (0) | 2023.01.04 |
| 문자열에서 동일한 UUID를 생성할 수 있는 방법이 있습니까? (0) | 2023.01.04 |
