7

Załóżmy, że mam następującą klasę, która będzie czytana intensywnie, ale tylko zapisywana okazjonalnie. Będzie on wykorzystywany w wielowątkowych aplikacji internetowej, więc to musi być bezpieczne wątek:Synchronizuj dostęp do zapisu do pola Volatile (tanie blokowanie odczytu i zapisu)

public class Foo { 
    private volatile String foo; 
    public String getFoo() { 
     return foo; 
    } 
    public synchronized String setFoo(String in) { 
     this.foo = in; 
    } 
} 

Java współbieżności (http://www.ibm.com/developerworks/java/library/j-jtp06197/index.html) stwierdza, że ​​jest to delikatny sposób, aby chronić dostęp do zapisu przy jednoczesnej poprawie odczytu. Czym jest silniejsza alternatywa dla tego wzoru? Lub jakąś alternatywę, jeśli foo będzie wymagało zmiany w środowisku ciężkim dla odczytu? Dziękuję Ci.

Odpowiedz

14

Lotny zapewnia szybki wątek bezpieczne lock-wolny dostęp do pola bez synchronizacji

private volatile String foo; 

public String getFoo() { 
    return foo; 
} 
public void setFoo(String in) { 
    this.foo = in; 
} 

nielotne rozwiązuje problemy 3 1) widoczności pamięć 2) zapisuje atomowych dla dwu- i długich polach 3) zakazuje praktykującym instrukcje reorganizację. Ale to nie wystarczy, jeśli potrzebujesz kilku operacji na polu jako jednej transakcji atomowej, takiej jak inkrementacja. Ten kod jest uszkodzony

private volatile int id; 

public void incrementId() { 
    id++; 
} 

bo jeśli 2 wątki simulataneously czytać i zwiększyć ją i zapisać wynik to wynik pierwszego przyrostu zostaną zastąpione w wyniku drugiej przyrostu. Aby temu zapobiec musimy użyć synchronizację

private int id; 

public synchronized int nextId() { 
     return ++id; 
} 

lub pakiet java.util.concurrent.atomic

private AtomicInteger id = new AtomicInteger(); 

public void incrementId() { 
    return id.incrementAndGet(); 
} 
+1

Oznaczenie zmiennej jako lotnej nie powoduje, że wątek jest bezpieczny. Jeśli wszystko, co robi OP, to czytanie/zapisywanie, to efektywnie jest bezpieczne dla wątków (nie byłoby to prawdą, gdyby wiele wątków zwiększało wartość zmiennej bazowej ...). –

+0

Czy jest więc jakaś sytuacja, w której zarówno lotny, jak i zsynchronizowany byłby odpowiedni? – oberger

+2

Jestem pewien, że nie ma takiej sytuacji. Jeśli zsynchronizujesz dostęp do pola, lotny jest zbędny. –

2

Jeśli to ustawienie foo wszystko robisz, to nie trzeba synchronizować metoda. sprawdzenie lotności odniesienia jest wystarczające.

+0

A jeśli zrobię więcej w metodzie setera? Takich jak operacja kopiowania lub podciągania. Czy po prostu synchronizuję lub używam obu? – oberger

+0

każda inna akcja w ustawieniu, która potrzebuje atomowości względem wartości ciągu, będzie wymagać użycia synchronizacji, która sprawi, że niestabilny modyfikator będzie bezużyteczny –

+1

@OwenBerger - jeśli musisz wykonać więcej pracy w ustawiaczu, to tak, zrobiłbyś trzeba zsynchronizować. jednak zmienna jest nadal przydatna w tym scenariuszu, ponieważ pozwala nie synchronizować gettera (zakładając, że nie dbasz o to, czy wywołujący do gettera dostaje starą wartość, podczas gdy inny rozmówca jest w ustawieniu). – jtahlborn

2

Na link pan powiedział, że jest to kod dla „rzadkie aktualizacje” Użycie:

@ThreadSafe 
public class CheesyCounter { 
    // Employs the cheap read-write lock trick 
    // All mutative operations MUST be done with the 'this' lock held 
    @GuardedBy("this") private volatile int value; 

    public int getValue() { return value; } 

    public synchronized int increment() { 
     return value++; 
    } 
} 

Sposób increment jest tylko przy użyciu zsynchronizowane bo robi więcej niż tylko ustawienie wartości value jak podano w opis, jeśli wszystko co robisz to this.foo = in;, który jest atomowy. W tekście "kruchość tego wzoru" oznacza, że ​​rzeczy mogą się bardzo szybko brudzić, gdy miesza się lotne i inne metody synchronizacji, aby zrobić coś więcej niż tylko proste przykłady. Zobacz pakiet java.util.concurrent.locks dla interfejsów Warunek i Blokowanie i klasy ReentrantLock. Myślę, że i używanie synchronizacji jest tym, co autor rozumie przez "mocniejsze alternatywy". Powinieneś także zobaczyć Object.wait, Object.notify i Object.notifyAll, jeśli jeszcze tego nie wiesz.

Powiązane problemy