2

저는 Java에 익숙하지 않고 Java의 동시성을 이해하려고합니다. 나는 자바 동시성에 꽤 인기 page에이 코드를 건너 온 탐험하는 동안 :이 코드가 중요 섹션에서 상호 배제를 위반하지 않습니까?

public class CrawledSites { 
    private List<String> crawledSites = new ArrayList<String>(); 
    private List<String> linkedSites = new ArrayList<String>(); 

    public void add(String site) { 
    synchronized (this) { 
     if (!crawledSites.contains(site)) { 
     linkedSites.add(site); 
     } 
    } 
    } 


/** 
    * Get next site to crawl. Can return null (if nothing to crawl) 
    */ 

    public String next() { 
    if (linkedSites.size() == 0) { 
     return null; 
    } 
    synchronized (this) { 
     // Need to check again if size has changed 
     if (linkedSites.size() > 0) { 
     String s = linkedSites.get(0); 
     linkedSites.remove(0); 
     crawledSites.add(s); 
     return s; 
     } 
     return null; 
    } 
    } 

} 

여기 선 아래로, 상호 배제을 위반 옆에 그() 함수를 생각 :

if (linkedSites.size() == 0) { 
    return null; 
} 

외부 보관 일부 스레드가 add() 또는 next()에서 동기화 된 블록 내에서 linkedSites를 수정하는 경우 다른 스레드에서 읽을 수 있습니다.

내가 잘못했을 경우를 대비하여 저를 시정하십시오.

+0

틀렸어. 목록에 대한 모든 액세스는 동기화되어야합니다. –

답변

2

당신은 맞다 - 나는 코드 작성자가 아마도 그들이 linkedSites 배열이 동기화 된 섹션으로 이동하기 전에 비어 있지 않은 것을 확인하여 약간의 시간을 절약 영리한 일을하고 있다고 생각 생각합니다. 동기화 된 섹션 내에서 크기가 다시 확인되므로 안전하지 않을 수 있습니다.

그러나 Java 메모리 모델은 읽기가 동기화 된 섹션에서도 수행되지 않는 한 next()를 호출하는 스레드가 마지막 스레드와 동일한 상태로 linkedSites를 볼 수 있다고 보장하지 않습니다. 따라서 이론적으로 next 거기에 데이터를 넣은 다른 스레드에도 배열이 비어있는 것으로 계속 볼 수 있습니다. 각 스레드는 잠재적으로 동기화 된 코드 블록에 의해서만 다른 스레드의 사본과 동기화되는 객체 데이터 사본을 가질 수 있습니다. 따라서 next를 호출하는 스레드가 배열을 비어있는 것으로 잘못 표시 할 수 있습니다.

1

귀하는 상호 배제라는 엄격한 의미에서 옳습니다. 그러나 멀티 스레드 프로그램에서도 예를 들어 액세스 할 때 모두을 동기화해야 할 필요는 없습니다. 읽기. 나는 전체 프로그램을 모른다. 그러나 아마도 next()은 아마 여러 번 호출 될 것이다. 스레드가 일부 항목을 놓친 경우 다른 항목이 나중에 catch됩니다. 그러나 당신이 말했듯이, 다른 사람들이 그 변화를 보게 될 것이라고 보장하지는 않습니다.

1

linkedSites.size()는 내부 그렇지 않으면 다른 스레드가 linkedSites에 대한 변경 사항을 볼 수 있고, 블록 동기화되어야한다.