4

상태가 여러 필드로 구성된 공유 객체에 대한 스레드 간 액세스를 동기화해야합니다. 말 :여러 필드 : volatile 또는 AtomicReference?

//writer 
shared.setA("state"); 
shared.setB(1); 

이제 내 질문하는 방법입니다

class Shared{ 
String a; Integer b; 
//constructor, getters and setters 
.... 
} 

나는 특정 지점에서 쓸 것이다

//readers 
shared.getA(); 
shared.getB(); 

단 하나의 스레드를하고,이 객체 읽기 가능한 많은 스레드를 읽기 스레드가 일관성없는 상태에서 공유 객체를 찾지 않도록합니다.

스레드 간의 일관성을 위해 volatile이 해결책이라고 많은 답변을 읽었지만 여러 필드에서 어떻게 작동하는지 모르겠습니다. 예, 충분하니?

volatile String a; volatile Integer b; 

또 다른 해결책은 AtomicReference, 예를 공유 객체는 불변하고 사용하는 것,

AtomicReference<Shared> shared = .... 

다음 작가가 참조를 교환 단지 의지 :

Shared prev = shared.get(); 
Shared newValue = new Shared("state",1); 
while (!shared.compareAndSet(prev, newValue)) 

는 방법입니다 옳은? 감사! 내 설정 공유 객체에서

업데이트ConcurrentHashMap<Id,Shared>에서 검색, 그래서 코멘트 동의 불변의 접근 방식을 사용하거나 이동 또는 모두 함께 공유에 업데이트를 동기화를 통해하는 방법. 그러나 완벽을 기하기 위해 ConcurrentHashMap<Id,AtomicReference<Shared>> 위의 솔루션이 실행 가능하거나 잘못되었거나 불필요한 것인지 여부를 확인하는 것이 좋습니다. 누구든지 설명 할 수 있습니까? 감사!

class Shared{ 
    private final String a; 
    private final int b; 
    //constructor, getters and NO setters 
} 

을 그리고 당신은 안전하게 휘발성 사용할 수있는 단 하나 명의 작가가 있다면, AtomicRefference의 필요가 없습니다 : 모든

+0

a와 b 모두에 원자 적으로 작성해야하는 경우 솔루션은 실제로 변경 불가능한 접근 방식을 사용합니다. AtomicReference는 필요하지 않습니다. 현재 공유 인스턴스에 간단한 휘발성 필드입니다. – Voo

+0

'Shared' 클래스를 불변으로 만들고 하나의 쓰레드 만 쓰면 atomic compareAndSet이 필요 없으며 단지'volatile Shared shared;'가 작업을 수행합니다. –

+0

[ReadWriteLock] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html) 사용은 어떻게됩니까? – Fildor

답변

1

먼저 당신이 Shared 불변해야한다. 정보가 업데이트되는 시점에서 이전 객체를 수정해서는 안되며, 새로운 객체를 만들어서 휘발성 문제에 할당해야합니다.

+0

당신은 휘발성 공유를 선언 한 다음 새로운 것으로 교체하겠습니까? 그러나 그러한 참조가 없지만지도 >에서 공유를 검색하면 어떻게됩니까? – legrass

+0

예, 그게 전부입니다. 여러 스레드가 동시에 참조를 쓰려고 할 때 AtomicRefference 및 CAS가 필요합니다. 당신이하고있는 일은 출판이라고 불리우며 단지 휘발성으로 가능합니다. – Mikhail

+0

알았어. 위의 편집에 대해서는 : 그런 참조가 없지만지도에서 공유 객체를 가져 오는 경우는 ? 내가 여기서 사용하는지도 >? – legrass

1

@Mikhail은 자신의 대답에서 Shared을 불변으로 만들고 전체 개체를 바꾸는 것이 좋은 방법이라고 말했습니다. 어떤 이유로 든 접근 방식을 사용하지 않거나 "사용할 수 없다"면 Shared의 모든 필드가 동일한 잠금 장치로 보호되고 그 필드가 동시에 수정 될 수 있습니다 (update 참조). 예를 들어), 일관성없는 상태에서 볼 수는 없습니다.

예컨대

class Shared { 
    private String a; 
    private String b; 
    public synchronized String getA() { 
    return a; 
    } 
    public synchronized String getB() { 
    return b; 
    } 
    public synchronized void update(String a, String b) { 
    this.a = a; 
    this.b = b; 
    } 
} 
1

당신이 모두를 작성해야하고 B 경우 함께 유지하는 일치, 예를 들어, 그들은 이름과 사회 보장 번호이며, 한 방법은 synchronized을 어디서나 사용하고, 단일, 결합 된 세터를 쓰는 것입니다.

public synchronized void setNameAndSSN(String name, int ssn) { 
    // do validation checking etc... 
    this.name = name; 
    this.ssn = ssn; 
} 

public synchronized String getName() { return this.name; } 

public synchronized int getSSN() { return this.ssn; } 

그렇지 않으면 독자는 새 이름이지만 이전 SSN을 사용하여 객체를 "볼"수 있습니다.

불변의 접근법 역시 의미가 있습니다.

1

휘발성 필드를 표시하거나 메소드를 동기화하는 것은 원 자성을 보장하지 않습니다.

작성자은 원 자성을 처리해야합니다.

작성자는 동기화 된 블록 내에서 모든 원자 집합을 (원자 적으로 업데이트해야 함) 호출해야합니다. 공유 객체의 모든 게터를 해결하려면이 들어 가 (공유) 동기화 된 { shared.setA() shared.setB() ... }

도 동기화해야합니다.

+0

IMO, 하나의 결합 된 동기화 된 설정기를 만들어 라이터가 실수를 할 수 없도록하는 것이 좋습니다. – user949300

+0

동의 함 .. 그러나 개발자가 항상 빈을 직접 수정할 수있는 권한이있는 것은 아닙니다. –