사람들이 단 한 줄의 코드 만 "동기화"하는 이유는 무엇입니까? "동기화"란 무엇입니까?동기화 된 코드 블록
public final void addListener(Listener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
편집 : 여러분 감사합니다. 모두에게 아주 좋은 답변!
사람들이 단 한 줄의 코드 만 "동기화"하는 이유는 무엇입니까? "동기화"란 무엇입니까?동기화 된 코드 블록
public final void addListener(Listener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
편집 : 여러분 감사합니다. 모두에게 아주 좋은 답변!
synchronized
은 여러 스레드가 동시에이 코드를 실행하려고하면 주어진 시간에 해당 스레드 중 하나만 블록 내에 허용된다는 것을 의미합니다. synchronized (listeners)
은 잠금 식별자로 listeners
을 사용합니다. 즉,이 제한은 해당 변수에서 동기화되는 모든 블록에 적용됩니다. 즉, 하나의 스레드가 해당 블록 중 하나에 속하면 다른 스레드가 그 블록 중 하나에 들어갈 수 없습니다.
블록에 하나의 함수 호출 만 있어도 함수가 많은 명령어로 구성되어 있고 컨트롤이 다른 스레드로 전환 될 수 있지만 첫 번째 매크로는 그 중간에 있습니다 기능. 함수가 스레드 안전이 아니면 데이터를 덮어 쓰는 등의 문제가 발생할 수 있습니다.
이 특별한 경우 함수 호출은 컬렉션에 값을 추가하는 것으로 구성됩니다. listeners
. 스레드로부터 안전한 컬렉션을 만드는 것은 불가능하지 않지만 대부분의 컬렉션은 여러 작성자에 대해 스레드로부터 안전하지 않습니다. 따라서 컬렉션이 엉망이되지 않도록하려면 synchronized
이 필요합니다.
EDIT :
public void Add(T item) {
items[length++] = item;
}
즉 length++
비트 원자 아니다 : 것들 엉망 수있는 방법의 일례를 제공하려면 length
가 items
배열의 요소의 개수 add
,이 간략화 된 구현을 가정 ; 읽기, 증가 및 쓰기로 구성되며 스레드는 그 중 하나 다음에 중단 될 수 있습니다.
public void Add(T item) {
int temp = length;
length = length + 1;
items[temp] = item;
}
지금 두 개의 스레드 T1을 가정 T2 동시에 추가 입력 : 그래서, 정말 무슨 일이 일어나고 있는지보고,이 비트를 다시 보자.여기에 사건의 하나 개의 가능한 세트는 다음과 같습니다
T1: int temp = length;
T2: int temp = length;
T2: length = length + 1;
T2: items[temp] = item;
T1: length = length + 1;
T1: items[temp] = item;
문제가 같은 값 두 스레드에 의해 temp
에 사용되는, 그래서 떠날 마지막 스레드가 첫 번째가 넣어 항목을 덮어 끝이; 및 맨 끝에 할당되지 않은 항목이 있습니다. length
그래서 우리는 선행 증가 사용할 수 있습니다 사용하는 다음 인덱스를 나타내는 경우도 도움이되지 않습니다
: 다시
public void Add(T item) {
items[++length] = item;
}
을, 우리는이를 다시 작성 :
이public void Add(T item) {
length = length + 1;
items[length] = item;
}
이제 이것은이다 가능한 이벤트 시퀀스 :
T1: length = length + 1;
T2: length = length + 1;
T2: items[length] = item;
T1: items[length] = item;
마지막 스레드가 다시 끝납니다. p가 첫 번째 항목을 덮어 쓰지 만 할당되지 않은 항목은 두 번째 - 마지막 항목입니다.
그래서 여러 스레드가 앱을 통해 분명한 답변으로 경쟁함에 따라 충돌이 발생하지 않습니다. Ajax 또는 Swing으로도 올바른 청취자가 듣고있는 올바른 객체를 갖고 있는지 확인하고자합니다.
내가 사용했던 이벤트 핸들러 툴킷 중 일부는 관리자가 청취자를 추상화하므로 모든 리스너를 arrayList에 넣은 다음 루프를 통해 바른 일치를 찾는 것과 같은 어리석은 일을 수행 할 필요가 없습니다. 객체와 청취자.
아직 안드로이드를 완성하지 못했지만 그 개념이 비슷하다고 확신합니다. 청취자에게 잘못된 객체를 가져 오는 것은 문제입니다.
HTH.
"단지 1 줄의 코드"가 아무 것도 아니기 때문입니다. 이 파일은 소스 코드의 한 줄일 수 있지만 실제 코드는 수 백 가지의 명령어가 될 수 있습니다. 중 하나가 작업 스위치에서 중단 될 수 있습니다.
listeners
을 (어떤 방법 으로든 사용하려는) 동기화하여 동기화하면 다른 실행 스레드가 사용자의 아래에서 러그를 당길 수 없으며 그 반대의 경우도 발생합니다.
표준 예 :
count++;
이 (이 프로세서는 메모리에 직접 동작 할 수 없기 때문이고, 레지스터에 변수를로드한다)
을int tmp=count;
tmp=tmp+1;
count=tmp;
에 뒤에서 확장
count
을로드하고 다른 스레드가 업데이트했을 수있는 업데이트 된 결과를 저장하는 사이에 이것은 업데이트가 l ost가 잘못된 동작을 야기 함
제공된 예제에서 한 줄의 코드를 "동기화"하는 것은 아니지만 리스너 객체를 잠그고 같은 객체에서 동기화되는 다른 스레드가 액세스하지 못하게합니다. .
당신의 addListener를 포함하는 클래스에 다른 방법을 가지고 가정 : 스레드 T는 청취자의 addListener의 호출에 객체를 잠근public void removeListener(Listener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
경우, S 때까지 동기화 된 블록 외부에 기다려야 할 것 스레드 thread T는 리스너 객체의 락을 해제합니다. 그런 다음 잠금을 획득하고 동기화 된 블록을 입력 한 다음 listers.remove (listener)를 호출합니다.
그러나 리스너 객체에 직접 액세스 한 코드는 잠금 획득을 기다리지 않습니다.
public void unsafeRemoveListener(Listener listener) {
listeners.remove(listener);
}
@zjs, [제안 된 개선] (http://stackoverflow.com/suggested-edits/117567)은이 답변을 개선하는 동안 게시물의 의미를 상당히 크게 변경한다는 점에 유의하십시오. [질문이나 답변의 의미를 대폭 변경하는 편집을 막을 수 있습니다.] (http://stackoverflow.com/privileges/edit) : _ 게시물의 의미를 변경하지 않고 명확하게 설명합니다. 귀하의 콘텐츠로 새로운 글을 올리시기 바랍니다. 일단 투표를 하셔서 여기에 의견을 남길 수 있습니다. :) – sarnold
왜 "이 코드의 한 줄"이 42 줄의 코드보다 더 많습니까? 거기에 이유가 있습니다 ;-) –