Czy jest zaleta stosowania metody zsynchronizowanej zamiast zsynchronizowanego bloku?

Czy ktos moze mi powiedziec zalete metody zsynchronizowanej nad zsynchronizowanym blokiem z przykladem?

Author: Mahozad, 2009-02-22

22 answers

czy ktos moze mi powiedziec zalete metody zsynchronizowanej nad zsynchronizowanym blokiem z przykladem? Dzięki.

Nie ma wyraźnej przewagi stosowania metody synchronizowanej nad blokiem.

Być może jedynym (ale nie nazwałbym tego zaletą) jest to, że nie musisz zawierać odniesienia do obiektu this.

Metoda:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

Blok:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}
Widzisz? Żadnej przewagi.

Bloki czy mają przewaga nad metodami, głównie w elastyczności, ponieważ można użyć innego obiektu jako blokady, podczas gdy synchronizacja metody zablokuje cały obiekt.

Porównaj:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

Vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

Również jeśli metoda rośnie, nadal możesz zachować zsynchronizowaną sekcję oddzieloną:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}
 397
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 15:15:51

Jedyna prawdziwa różnica polega na tym, że zsynchronizowany blok może wybrać, na którym obiekcie się synchronizuje. Metoda zsynchronizowana może używać tylko 'this' (lub odpowiedniej instancji klasy dla metody klasy zsynchronizowanej). Na przykład są one semantycznie równoważne:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

Ten ostatni jest bardziej elastyczny, ponieważ może konkurować o powiązaną blokadę dowolnego obiektu, często zmiennej członkowskiej. Jest to również bardziej szczegółowe, ponieważ możesz mieć równoczesne wykonywanie kodu przed i po blok, ale nadal w ramach metody. Oczywiście równie łatwo można użyć metody zsynchronizowanej poprzez refaktoryzację współbieżnego kodu w osobne, niezsynchronizowane metody. Użyj tego, co sprawia, że kod jest bardziej zrozumiały.

 136
Author: jcrossley3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-22 03:46:39

Metoda Synchronizowana

Plusy:

  • twoje IDE może wskazać zsynchronizowane metody.
  • Składnia jest bardziej zwarta.
  • wymusza dzielenie zsynchronizowanych bloków na oddzielne metody.

Wady:

  • synchronizuje się z tym i dzięki temu możliwe jest również synchronizowanie się z tym.
  • trudniej jest przenieść kod poza zsynchronizowany blok.

Synchronized block

Plusy:

  • pozwala na użycie prywatna zmienna dla blokady, a więc zmuszająca blokadę do pozostania wewnątrz klasy.
  • zsynchronizowane bloki można znaleźć poprzez wyszukiwanie odniesień do zmiennej.

Wady:

  • składnia jest bardziej skomplikowana, przez co kod jest trudniejszy do odczytania.

Osobiście wolę używać metod zsynchronizowanych z klasami skupionymi tylko na tym, co wymaga synchronizacji. Taka klasa powinna być jak najmniejsza, a więc powinna być łatwa do przejrzenia synchronizacja. Inni nie powinni przejmować się synchronizacją.

 75
Author: iny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-09 19:22:00

Główna różnica polega na tym, że jeśli używasz zsynchronizowanego bloku, możesz zablokować obiekt inny niż ten , który pozwala być znacznie bardziej elastyczny.

Załóżmy, że masz kolejkę komunikatów oraz wielu producentów i konsumentów komunikatów. Nie chcemy, aby producenci ingerowali w siebie, ale konsumenci powinni mieć możliwość pobierania wiadomości bez konieczności oczekiwania na producentów. Więc po prostu tworzymy obiekt

Object writeLock = new Object();

I od teraz za każdym razem, gdy producent chce dodać nowa wiadomość po prostu blokujemy:

synchronized(writeLock){
  // do something
}

Więc konsumenci mogą nadal czytać, a producenci zostaną zablokowani.

 35
Author: cdecker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-19 10:44:44

Metoda synchronizowana

Metody zsynchronizowane mają dwa efekty.
Po pierwsze, gdy jeden wątek wykonuje zsynchronizowaną metodę dla obiektu, wszystkie inne wątki, które wywołują zsynchronizowane metody dla tego samego bloku obiektu (wstrzymują wykonanie), dopóki pierwszy wątek nie zostanie wykonany z obiektem.

Po drugie, gdy zsynchronizowana metoda kończy działanie, automatycznie ustanawia związek happens-before z każdym kolejnym wywołaniem zsynchronizowanej metody dla tego samego obiekt. Gwarantuje to, że zmiany stanu obiektu są widoczne dla wszystkich wątków.

Zauważ, że konstruktorów nie można zsynchronizować - użycie słowa kluczowego zsynchronizowanego z konstruktorem jest błędem składni. Synchronizacja konstruktorów nie ma sensu, ponieważ tylko wątek, który tworzy obiekt, powinien mieć do niego dostęp podczas jego konstruowania.

Synchronized Statement

W przeciwieństwie do metod zsynchronizowanych, polecenia zsynchronizowane muszą określać obiekt, który zapewnia wewnętrzną blokadę: najczęściej używam tego do synchronizacji dostępu do listy lub mapy, ale nie chcę blokować dostępu do wszystkich metod obiektu.

P: wewnętrzne blokady i synchronizacja Synchronizacja jest zbudowana wokół wewnętrznej jednostki znanej jako wewnętrzna blokada lub blokada monitora. (Specyfikacja API często odnosi się do tego podmiotu po prostu jako " monitor.") Blokady wewnętrzne odgrywają rolę w obu aspektach synchronizacji: wymuszają wyłączny dostęp do stanu obiektu i nawiązywanie relacji, które są niezbędne do widoczności.

Każdy obiekt ma przypisany do niego wewnętrzny zamek. Zgodnie z konwencją, wątek, który wymaga wyłącznego i spójnego dostępu do pól obiektu, musi nabyć wewnętrzną blokadę obiektu przed uzyskaniem dostępu do nich, a następnie zwolnić wewnętrzną blokadę, gdy zostanie to wykonane z nimi. Mówi się, że gwint jest właścicielem wewnętrznego zamka między czasem, w którym nabył zamek i zwolnił zamek. Dopóki wątek posiada wewnętrzny zamek, żaden inny gwint nie może uzyskać tego samego zamka. Drugi wątek zablokuje się, gdy spróbuje zdobyć blokadę.

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

Sprawdzanie krzyżowe różnych wyjść metodą zsynchronizowaną, blokową i bez synchronizacji.

 29
Author: sudheer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-07 16:15:36

Notatka: static zsynchronizowane metody i bloki działają na obiekcie klasy.

public class MyClass {
   // locks MyClass.class
   public static synchronized void foo() {
// do something
   }

   // similar
   public static void foo() {
      synchronized(MyClass.class) {
// do something
      }
   }
}
 27
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-22 03:30:31

Kiedy kompilator Javy konwertuje kod źródłowy na kod bajtowy, obsługuje metody zsynchronizowane i bloki w różny sposób.

Gdy JVM wykonuje zsynchronizowaną metodę, wątek wykonujący identyfikuje, że struktura method_info metody ma ustawiony znacznik ACC_SYNCHRONIZED, a następnie automatycznie przejmuje blokadę obiektu, wywołuje metodę i zwalnia blokadę. Jeśli wystąpi wyjątek, wątek automatycznie zwalnia blokadę.

Synchronizacja metody block, z drugiej strony, omija wbudowaną obsługę JVM do pozyskiwania blokady obiektu i obsługi wyjątków i wymaga, aby funkcjonalność była jawnie zapisana w kodzie bajtowym. Jeśli odczytasz kod bajtowy metody z zsynchronizowanym blokiem, zobaczysz więcej niż tuzin dodatkowych operacji do zarządzania tą funkcjonalnością.

Pokazuje wywołania generujące zarówno zsynchronizowaną metodę, jak i zsynchronizowany blok:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

    public int synchronizedBlockGet() {
        synchronized( this ) {
            return i;
        }
    }
}

Metoda synchronizedMethodGet() generuje następujący bajt kod:

0:  aload_0
1:  getfield
2:  nop
3:  iconst_m1
4:  ireturn

A oto kod bajtowy z metody synchronizedBlockGet():

0:  aload_0
1:  dup
2:  astore_1
3:  monitorenter
4:  aload_0
5:  getfield
6:  nop
7:  iconst_m1
8:  aload_1
9:  monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow

Jedna znacząca różnica między metodą synchronizowaną a blokiem polega na tym, że zsynchronizowany blok generalnie zmniejsza zakres blokady. Ponieważ zakres blokady jest odwrotnie proporcjonalny do wydajności, zawsze lepiej jest zablokować tylko krytyczną sekcję kodu. Jednym z najlepszych przykładów użycia bloku synchronicznego jest podwójnie sprawdzane blokowanie we wzorze Singletona gdzie zamiast metody blokowania całego getInstance() mamy blokuje tylko krytyczną sekcję kodu, która jest używana do tworzenia instancji Singleton. To znacznie poprawia wydajność, ponieważ blokowanie jest wymagane tylko jeden lub dwa razy.

Podczas korzystania z metod zsynchronizowanych, musisz zachować szczególną ostrożność, jeśli mieszasz zarówno statyczne metody zsynchronizowane, jak i niestatyczne metody zsynchronizowane.

 17
Author: Mohammad Adil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-23 08:05:58

Najczęściej używam tego do synchronizacji dostępu do listy lub mapy, ale nie chcę blokować dostępu do wszystkich metod obiektu.

W poniższym kodzie jeden wątek modyfikujący listę nie zablokuje oczekiwania na wątek modyfikujący mapę. Gdyby metody były zsynchronizowane na obiekcie, to każda metoda musiałaby czekać, mimo że wprowadzane przez nią modyfikacje nie byłyby sprzeczne.

private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();

public void put( String s, Bar b ) {
  synchronized( myMap ) {
    myMap.put( s,b );
    // then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public void hasKey( String s, ) {
  synchronized( myMap ) {
    myMap.hasKey( s );
  }
}

public void add( Foo f ) {
  synchronized( myList ) {
    myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public Thing getMedianFoo() {
  Foo med = null;
  synchronized( myList ) {
    Collections.sort(myList);
    med = myList.get(myList.size()/2); 
  }
  return med;
}
 12
Author: Clint,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-22 07:04:38

Dzięki zsynchronizowanym blokom możesz mieć wiele synchronizatorów, dzięki czemu wiele jednoczesnych, ale nie kolidujących rzeczy może działać w tym samym czasie.

 6
Author: Paul Tomblin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-22 03:19:18

Zsynchronizowane metody można sprawdzać za pomocą API reflection. Może to być przydatne do testowania niektórych umów, np. wszystkie metody w modelu są zsynchronizowane .

Poniższy fragment wyświetla wszystkie zsynchronizowane metody Hashtable:

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}
 6
Author: Kojotak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-20 08:45:10

Ważna uwaga dotycząca używania zsynchronizowanego bloku: uważaj, czego używasz jako obiektu blokady!

Urywek kodu z user2277816 powyżej ilustruje ten punkt w tym, że odniesienie do literała łańcuchowego jest używane jako obiekt blokujący. Zdaj sobie sprawę, że literały ciągów są automatycznie internowane w Javie i powinieneś zacząć dostrzegać problem: każdy fragment kodu, który synchronizuje się na dosłownym "lock", dzieli tę samą blokadę! Może to łatwo prowadzić do impasów z zupełnie niepowiązanymi kawałkami kod.

To nie tylko obiekty łańcuchowe, na które trzeba uważać. Boxed primitives są również zagrożeniem, ponieważ autoboxing i metody valueOf mogą ponownie użyć tych samych obiektów, w zależności od wartości.

Aby uzyskać więcej informacji zobacz: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

 5
Author: Søren Boisen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-12 11:41:31

Często używanie blokady na poziomie metody jest zbyt niegrzeczne. Po co zamykać fragment kodu, który nie ma dostępu do udostępnionych zasobów, blokując całą metodę. Ponieważ każdy obiekt ma blokadę, można tworzyć atrapy obiektów w celu zaimplementowania synchronizacji poziomu bloków. poziom bloku jest bardziej wydajny, ponieważ nie blokuje całej metody.

Oto przykład

Poziom Metody

class MethodLevel {

  //shared among threads
SharedResource x, y ;

public void synchronized method1() {
   //multiple threads can't access
}
public void synchronized method2() {
  //multiple threads can't access
}

 public void method3() {
  //not synchronized
  //multiple threads can access
 }
}

Blok Poziom

class BlockLevel {
  //shared among threads
  SharedResource x, y ;

  //dummy objects for locking
  Object xLock = new Object();
  Object yLock = new Object();

    public void method1() {
     synchronized(xLock){
    //access x here. thread safe
    }

    //do something here but don't use SharedResource x, y
    // because will not be thread-safe
     synchronized(xLock) {
       synchronized(yLock) {
      //access x,y here. thread safe
      }
     }

     //do something here but don't use SharedResource x, y
     //because will not be thread-safe
    }//end of method1
 }

[Edit]

Dla Collection Jak Vector i Hashtable są zsynchronizowane, gdy ArrayList lub HashMap nie są i musisz ustawić zsynchronizowane słowo kluczowe lub wywołać metodę zsynchronizowaną kolekcji:

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
 5
Author: Maxim Shoustin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-10 11:41:40

Metoda Synchronized służy do blokowania wszystkich obiektów Zsynchronizowany blok jest używany do blokowania określonego obiektu

 4
Author: kishore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-14 06:35:56

Jedyna różnica : zsynchronizowane bloki pozwalają na blokowanie granulatu w przeciwieństwie do metody zsynchronizowanej

Zasadniczo synchronized blok lub metody zostały użyte do napisania bezpiecznego kodu wątku, unikając błędów niespójności pamięci.

To pytanie jest bardzo stare i wiele rzeczy zmieniło się w ciągu ostatnich 7 lat. Dla bezpieczeństwa wątku wprowadzono nowe konstrukcje programistyczne.

Możesz osiągnąć bezpieczeństwo wątku używając Zaawansowanego współbieżnego API zamiast synchronied bloki. Ta dokumentacja Strona zapewnia dobre konstrukcje programistyczne w celu osiągnięcia bezpieczeństwa wątku.

Zablokuj Obiekty obsługa idiomów blokujących, które upraszczają wiele jednoczesnych aplikacji.

Executors definiowanie interfejsu API wysokiego poziomu do uruchamiania i zarządzania wątkami. Implementacje executora dostarczane przez Javę.util.współbieżne zarządzanie pulą wątków nadaje się do zastosowań na dużą skalę.

Współbieżne Kolekcje ułatwiają zarządzanie dużymi zbiorami danych i mogą znacznie zmniejszyć potrzebę synchronizacji.

Zmienne atomowe mają funkcje, które minimalizują synchronizację i pomagają uniknąć błędów spójności pamięci.

ThreadLocalRandom (w JDK 7) zapewnia efektywne generowanie liczb pseudorandomowych z wielu wątków.

Lepszym zamiennikiem dla synchronized jest ReentrantLock , który wykorzystuje Lock API

Blokada wzajemnego wykluczania reentrant z tym samym podstawowym zachowaniem i semantyką, co ukryta blokada monitora, do której dostęp uzyskuje się przy użyciu zsynchronizowanych metod i instrukcji, ale z rozszerzonymi możliwościami.

Przykład z zamkami:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Zobacz java.util.współbieżne i java.util./ align = "left" / atomowe Pakiety również dla innych konstrukcji programistycznych.

Zobacz też to powiązane pytanie:

Synchronizacja vs Lock

 4
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-14 15:47:36

Ogólnie rzecz biorąc, są one w większości takie same, poza tym, że są jawne w odniesieniu do monitora obiektu, który jest używany, a dorozumiany ten obiekt. Jednym z minusów zsynchronizowanych metod, które myślę, że jest czasami pomijane, jest to, że przy użyciu" tego " odniesienia do synchronizacji na pozostawiają otwartą możliwość blokowania obiektów zewnętrznych na tym samym obiekcie. To może być bardzo subtelny błąd, jeśli na niego wpadniesz. Synchronizacja na wewnętrznym jawnym obiekcie lub innym istniejącym polu może tego uniknąć problem, całkowicie obudowując synchronizację.

 3
Author: Alex Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-22 20:28:59

Jak już wspomniano, synchronized block może używać zmiennej zdefiniowanej przez użytkownika jako obiektu lock, gdy funkcja synchronized używa tylko "this". I oczywiście możesz manipulować obszarami swojej funkcji, które powinny być zsynchronizowane. Ale wszyscy mówią, że nie ma różnicy między zsynchronizowaną funkcją a blokiem, który obejmuje całą funkcję używając "tego" jako obiektu blokady. Nie jest to prawdą, różnica polega na kodzie bajtowym, który zostanie wygenerowany w obu sytuacjach. W przypadku zsynchronizowanego użycia bloku należy przydzielona zmienna lokalna, która zawiera odniesienie do "this". W rezultacie będziemy mieli trochę większy rozmiar dla funkcji(nie dotyczy, jeśli masz tylko kilka funkcji).

Bardziej szczegółowe wyjaśnienie różnicy można znaleźć tutaj: http://www.artima.com/insidejvm/ed2/threadsynchP.html

 2
Author: Roman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-16 08:43:36

W przypadku metod zsynchronizowanych, blokada zostanie uzyskana na obiekcie. Ale jeśli pójdziesz z synchronized block masz możliwość określenia obiektu, na którym zostanie uzyskana blokada.

Przykład:

    Class Example {
    String test = "abc";
    // lock will be acquired on String  test object.
    synchronized (test) {
        // do something
    }

   lock will be acquired on Example Object
   public synchronized void testMethod() {
     // do some thing
   } 

   }
 2
Author: Srinu Yarru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-13 11:54:37

Wiem, że to stare pytanie, ale po moim szybkim przeczytaniu odpowiedzi tutaj, tak naprawdę nie widziałem nikogo wspomnieć, że czasami synchronized Metoda może być źle Blokada.
Z języka Java współbieżność w praktyce (str. 72):

public class ListHelper<E> {
  public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...

public syncrhonized boolean putIfAbsent(E x) {
 boolean absent = !list.contains(x);
if(absent) {
 list.add(x);
}
return absent;
}

Powyższy kod ma wygląd jako bezpieczny dla wątku. Jednak w rzeczywistości tak nie jest. W tym przypadku blokada jest uzyskiwana na instancji klasy. Istnieje jednak możliwość modyfikacji listy przez inny wątek nie używając tej metody. Poprawnym podejściem byłoby użycie

public boolean putIfAbsent(E x) {
 synchronized(list) {
  boolean absent = !list.contains(x);
  if(absent) {
    list.add(x);
  }
  return absent;
}
}

Powyższy kod blokuje wszystkie wątki próbujące zmodyfikować listę od modyfikacji listy aż do zakończenia zsynchronizowanego bloku.

 2
Author: aarbor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-25 17:04:07

W praktyce zaletą metod zsynchronizowanych nad zsynchronizowanymi blokami jest to, że są one bardziej odporne na idiotyzm; ponieważ nie możesz wybrać dowolnego obiektu do zablokowania, nie możesz nadużywać składni zsynchronizowanych metod do robienia głupich rzeczy, takich jak blokowanie na literalnym łańcuchu lub blokowanie zawartości zmiennego pola, które zmienia się spod wątków.

Z drugiej strony, przy zsynchronizowanych metodach nie można zabezpieczyć zamka przed przejęciem przez jakiekolwiek wątek, który może uzyskać odniesienie do obiektu.

Więc używanie zsynchronizowanych jako modyfikatorów metod jest lepsze w ochronie krów-orków przed zranieniem samych siebie, podczas gdy używanie zsynchronizowanych bloków w połączeniu z prywatnymi obiektami blokady końcowej jest lepsze w ochronie własnego kodu przed krowami-orków.

 2
Author: Nathan Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-12 13:47:47

Z podsumowania specyfikacji Javy: http://www.cs.cornell.edu/andru/javaspec/17.doc.html

Polecenie zsynchronizowane (§14.17) oblicza odniesienie do obiektu; następnie próbuje wykonać akcję blokady na tym obiekcie i nie kontynuuj, aż akcja blokady zakończy się pomyślnie. ...

Metoda zsynchronizowana (§8.4.3.5) automatycznie wykonuje akcję blokady gdy jest wywoływany; jego ciało nie jest wykonywane, dopóki akcja blokująca nie zakończone sukcesem. Jeśli metoda jest instancją metody , to blokuje blokadę powiązaną z instancją, dla której została wywołana (czyli obiekt, który będzie znany jako ten podczas wykonywania ciało metody). Jeśli metoda jest statyczna , blokuje blokada powiązana z obiektem klasy, który reprezentuje klasę w której metoda jest zdefiniowana. ...

Na podstawie tych opisów powiedziałbym, że większość poprzednich odpowiedzi jest poprawna, a metoda zsynchronizowana może być szczególnie przydatna dla metod statycznych, gdzie w przeciwnym razie musiałbyś dowiedzieć się, jak uzyskać "obiekt klasy, który reprezentuje klasę, w której metoda została zdefiniowana."

Edit: początkowo myślałem, że są to cytaty rzeczywistej specyfikacji Javy. Wyjaśnione, że ta strona jest tylko podsumowanie / Wyjaśnienie spec

 1
Author: Josiah Yoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-19 13:15:08

TLDR; nie używa modyfikatora synchronized ani wyrażenia synchronized(this){...}, ale synchronized(myLock){...} Gdzie myLock jest polem ostatniej instancji przechowującym obiekt prywatny.


Różnica między użyciem modyfikatora synchronized w deklaracji metody a wyrażeniem synchronized(..){ } w ciele metody jest następująca:

  • modyfikator synchronized podany na podpisie metody
    1. jest widoczny w wygenerowanym JavaDoc,
    2. jest programowo wyznaczalna poprzez odbicie podczas testowania modyfikatora metody dla modyfikatora .Zsynchronizowane ,
    3. wymaga mniej typowania i wcięcia w porównaniu do synchronized(this) { .... } i
    4. (w zależności od Twojego IDE) jest widoczny w konturze klasy i uzupełnianiu kodu,
    5. używa obiektu this jako blokady, gdy jest zadeklarowana w metodzie niestatycznej lub klasy zamkniętej, gdy jest zadeklarowana w metodzie statycznej.
  • wyrażenie synchronized(...){...} pozwala na
    1. aby zsynchronizować tylko wykonanie części ciała metody,
    2. Do użycia wewnątrz konstruktora lub bloku inicjalizacji (static ),
  • aby wybrać obiekt blokady, który kontroluje zsynchronizowany dostęp.

Jednak użycie modyfikatora synchronized lub synchronized(...) {...} z this jako obiektem blokady (jak w synchronized(this) {...}), ma tę samą wadę. Oba używają własnej instancji jako obiektu lock do synchronizacji. Jest to niebezpieczne, ponieważ nie tylko sam obiekt, ale każdy inny zewnętrzny obiekt / kod, który zawiera odniesienie do tego obiektu, może również użyć go jako blokady synchronizacji z potencjalnie poważnymi skutkami ubocznymi (degradacja wydajności i blokady ).

Dlatego najlepszą praktyką jest nie używać modyfikatora synchronized ani wyrażenia synchronized(...) w połączeniu z this jako obiektu lock, ale obiektu lock prywatnego dla tego obiektu. Na przykład:

public class MyService {
    private final lock = new Object();

    public void doThis() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }

    public void doThat() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }
}

Można również używać wielu obiektów lock, ale należy zachować szczególną ostrożność, aby to zapewnić nie powoduje martwych punktów w przypadku zagnieżdżenia.

public class MyService {
    private final lock1 = new Object();
    private final lock2 = new Object();

    public void doThis() {
       synchronized(lock1) {
          synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThat() and doMore().
          }
    }

    public void doThat() {
       synchronized(lock1) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doMore() may execute concurrently
        }
    }

    public void doMore() {
       synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doThat() may execute concurrently
        }
    }
}
 1
Author: Sebastian Thomschke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-15 22:12:36

Synchronizacja z wątkami. 1) nigdy nie używaj synchronized (this) w wątku, który nie działa. Synchronizacja z (this) wykorzystuje bieżący wątek jako obiekt blokujący wątek. Ponieważ każdy wątek jest niezależny od innych wątków, nie ma koordynacji synchronizacji. 2) Testy kodu pokazują, że w Javie 1.6 na Macu synchronizacja metod nie działa. 3) synchronized(lockObj) gdzie lockObj jest wspólnym wspólnym obiektem wszystkich wątków synchronizujących się na nim będzie działać. 4) ReenterantLock.lock() i .unlock () działa. Zobacz samouczki Java dla tego.

Poniższy kod pokazuje te punkty. Zawiera również Wektor bezpieczny dla wątków, który byłby zastąpiony ArrayList, aby pokazać, że wiele wątków dodawanych do wektora nie traci żadnych informacji, podczas gdy to samo z ArrayList może stracić informacje. 0) aktualny kod pokazuje utratę informacji z powodu warunków wyścigu A) Skomentuj bieżącą linię oznaczoną jako linia i odkomentuj linię A nad nią, następnie uruchom, metoda traci dane, ale nie powinno. B) Odwrotny krok A, odkomentowanie B i / / koniec bloku }. Następnie uruchom, aby zobaczyć wyniki bez utraty danych C) komentarz B, uncomment C. Uruchom, patrz synchronizacja na (to) traci dane, zgodnie z oczekiwaniami. Nie mam czasu na ukończenie wszystkich wariacji, mam nadzieję, że to pomoże. Jeśli synchronizacja w (this) lub metoda synchronizacji działa, proszę podać, jaką wersję Java i OS testowałeś. Dziękuję.

import java.util.*;

/** RaceCondition - Shows that when multiple threads compete for resources 
     thread one may grab the resource expecting to update a particular 
     area but is removed from the CPU before finishing.  Thread one still 
     points to that resource.  Then thread two grabs that resource and 
     completes the update.  Then thread one gets to complete the update, 
     which over writes thread two's work.
     DEMO:  1) Run as is - see missing counts from race condition, Run severa times, values change  
            2) Uncomment "synchronized(countLock){ }" - see counts work
            Synchronized creates a lock on that block of code, no other threads can 
            execute code within a block that another thread has a lock.
        3) Comment ArrayList, unComment Vector - See no loss in collection
            Vectors work like ArrayList, but Vectors are "Thread Safe"
         May use this code as long as attribution to the author remains intact.
     /mf
*/ 

public class RaceCondition {
    private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
//  private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)

    private String countLock="lock";    // Object use for locking the raceCount
    private int raceCount = 0;        // simple add 1 to this counter
    private int MAX = 10000;        // Do this 10,000 times
    private int NUM_THREADS = 100;    // Create 100 threads

    public static void main(String [] args) {
    new RaceCondition();
    }

    public RaceCondition() {
    ArrayList<Thread> arT = new ArrayList<Thread>();

    // Create thread objects, add them to an array list
    for( int i=0; i<NUM_THREADS; i++){
        Thread rt = new RaceThread( ); // i );
        arT.add( rt );
    }

    // Start all object at once.
    for( Thread rt : arT ){
        rt.start();
    }

    // Wait for all threads to finish before we can print totals created by threads
    for( int i=0; i<NUM_THREADS; i++){
        try { arT.get(i).join(); }
        catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
    }

    // All threads finished, print the summary information.
    // (Try to print this informaiton without the join loop above)
    System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
                MAX*NUM_THREADS, raceList.size(), raceCount );
    System.out.printf("Array lost %,d. Count lost %,d\n",
             MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
    }   // end RaceCondition constructor



    class RaceThread extends Thread {
    public void run() {
        for ( int i=0; i<MAX; i++){
        try {
            update( i );        
        }    // These  catches show when one thread steps on another's values
        catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
        catch( OutOfMemoryError oome ) { System.out.print("O"); }
        }
    }

    // so we don't lose counts, need to synchronize on some object, not primitive
    // Created "countLock" to show how this can work.
    // Comment out the synchronized and ending {, see that we lose counts.

//    public synchronized void update(int i){   // use A
    public void update(int i){                  // remove this when adding A
//      synchronized(countLock){            // or B
//      synchronized(this){             // or C
        raceCount = raceCount + 1;
        raceList.add( i );      // use Vector  
//          }           // end block for B or C
    }   // end update

    }   // end RaceThread inner class


} // end RaceCondition outter class
 -3
Author: user2277816,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-14 16:31:04