2011-10-07 4 views
2

사람들이 단 한 줄의 코드 만 "동기화"하는 이유는 무엇입니까? "동기화"란 무엇입니까?동기화 된 코드 블록

public final void addListener(Listener listener) { 
    synchronized (listeners) { 
    listeners.add(listener); 
    } 
} 

편집 : 여러분 감사합니다. 모두에게 아주 좋은 답변!

+0

왜 "이 코드의 한 줄"이 42 줄의 코드보다 더 많습니까? 거기에 이유가 있습니다 ;-) –

답변

8

synchronized은 여러 스레드가 동시에이 코드를 실행하려고하면 주어진 시간에 해당 스레드 중 하나만 블록 내에 허용된다는 것을 의미합니다. synchronized (listeners)은 잠금 식별자로 listeners을 사용합니다. 즉,이 제한은 해당 변수에서 동기화되는 모든 블록에 적용됩니다. 즉, 하나의 스레드가 해당 블록 중 하나에 속하면 다른 스레드가 그 블록 중 하나에 들어갈 수 없습니다.

블록에 하나의 함수 호출 만 있어도 함수가 많은 명령어로 구성되어 있고 컨트롤이 다른 스레드로 전환 될 수 있지만 첫 번째 매크로는 그 중간에 있습니다 기능. 함수가 스레드 안전이 아니면 데이터를 덮어 쓰는 등의 문제가 발생할 수 있습니다.

이 특별한 경우 함수 호출은 컬렉션에 값을 추가하는 것으로 구성됩니다. listeners. 스레드로부터 안전한 컬렉션을 만드는 것은 불가능하지 않지만 대부분의 컬렉션은 여러 작성자에 대해 스레드로부터 안전하지 않습니다. 따라서 컬렉션이 엉망이되지 않도록하려면 synchronized이 필요합니다.

EDIT :

public void Add(T item) { 
    items[length++] = item; 
} 

length++ 비트 원자 아니다 : 것들 엉망 수있는 방법의 일례를 제공하려면 lengthitems 배열의 요소의 개수 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가 첫 번째 항목을 덮어 쓰지 만 할당되지 않은 항목은 두 번째 - 마지막 항목입니다.

+2

이 코드 조각뿐만 아니라 '청취자'에 동기화되는 코드 조각도 있습니다. 자물쇠는 코드가 아니라 객체에 있습니다. – paxdiablo

+0

@paxdiablo : 예, 물론, 그 점을 잊어 버렸습니다. 편집 중 ... –

+0

+1 명확하게하기 위해. – paxdiablo

0

그래서 여러 스레드가 앱을 통해 분명한 답변으로 경쟁함에 따라 충돌이 발생하지 않습니다. Ajax 또는 Swing으로도 올바른 청취자가 듣고있는 올바른 객체를 갖고 있는지 확인하고자합니다.

내가 사용했던 이벤트 핸들러 툴킷 중 일부는 관리자가 청취자를 추상화하므로 모든 리스너를 arrayList에 넣은 다음 루프를 통해 바른 일치를 찾는 것과 같은 어리석은 일을 수행 할 필요가 없습니다. 객체와 청취자.

아직 안드로이드를 완성하지 못했지만 그 개념이 비슷하다고 확신합니다. 청취자에게 잘못된 객체를 가져 오는 것은 문제입니다.

HTH.

3

"단지 1 줄의 코드"가 아무 것도 아니기 때문입니다. 이 파일은 소스 코드의 한 줄일 수 있지만 실제 코드는 수 백 가지의 명령어가 될 수 있습니다. 중 하나가 작업 스위치에서 중단 될 수 있습니다.

listeners을 (어떤 방법 으로든 사용하려는) 동기화하여 동기화하면 다른 실행 스레드가 사용자의 아래에서 러그를 당길 수 없으며 그 반대의 경우도 발생합니다.

1

표준 예 :

count++; 

이 (이 프로세서는 메모리에 직접 동작 할 수 없기 때문이고, 레지스터에 변수를로드한다)

int tmp=count; 
tmp=tmp+1; 
count=tmp; 

에 뒤에서 확장

count을로드하고 다른 스레드가 업데이트했을 수있는 업데이트 된 결과를 저장하는 사이에 이것은 업데이트가 l ost가 잘못된 동작을 야기 함

1

제공된 예제에서 한 줄의 코드를 "동기화"하는 것은 아니지만 리스너 객체를 잠그고 같은 객체에서 동기화되는 다른 스레드가 액세스하지 못하게합니다. .

당신의 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); 
} 
+0

@zjs, [제안 된 개선] (http://stackoverflow.com/suggested-edits/117567)은이 답변을 개선하는 동안 게시물의 의미를 상당히 크게 변경한다는 점에 유의하십시오. [질문이나 답변의 의미를 대폭 변경하는 편집을 막을 수 있습니다.] (http://stackoverflow.com/privileges/edit) : _ 게시물의 의미를 변경하지 않고 명확하게 설명합니다. 귀하의 콘텐츠로 새로운 글을 올리시기 바랍니다. 일단 투표를 하셔서 여기에 의견을 남길 수 있습니다. :) – sarnold

관련 문제