Java'da en sık karşılaştığınız eşzamanlılık sorunu nedir? [kapalı]


192

Bu, Java'daki yaygın eşzamanlılık sorunları hakkında bir ankettir. Bir örnek, klasik kilitlenme veya yarış durumu veya belki de Swing'deki EDT diş açma hataları olabilir. Hem olası sorunların genişliği hem de hangi sorunların en yaygın olduğu ile ilgileniyorum. Bu nedenle, lütfen yorum başına bir Java eşzamanlılık hatası için belirli bir cevap bırakın ve karşılaştığınız birini görürseniz oy verin.


16
Bu neden kapalı? Bu, hem Java'da eşzamanlılık isteyen ya da hem de diğer Java geliştiricileri tarafından en çok eşzamanlılık hatası sınıflarının gözlemlendiği konusunda bir fikir sahibi olmak için yararlıdır.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

@ Uzunpok Kapatma mesajı neden kapandığını açıklar. Bu belirli bir "doğru" cevabı olan bir soru değil, daha çok bir anket / liste sorusudur. Yığın Taşması bu tür soruları barındırmayı amaçlamaz. Bu politikaya katılmıyorsanız, meta ile görüşmek isteyebilirsiniz .
Andrzej Doyle

7
Sanırım topluluk, bu makale günde 100'den fazla görüntüleme alıyor gibi katılmıyor! Özellikle düzeltme eşzamanlılık sorunları için tasarlanmış bir statik analiz aracı geliştirilmesi ile ilgili ediyorum ben bunu çok yararlı bulduk contemplateltd.com/threadsafe . Sık karşılaşılan eşzamanlılık sorunlarından oluşan bir bankaya sahip olmak ThreadSafe'i test etmek ve geliştirmek için harikadır.
Craig Manson

Java Concurrency için kod inceleme kontrol listesi , bu sorunun yanıtlarında belirtilen tuzakların çoğunu günlük kod incelemeleri için uygun bir biçimde sindirir.
leventov

Yanıtlar:


125

Gördüğüm en yaygın eşzamanlılık sorunu, bir iş parçacığı tarafından yazılan bir alanın farklı bir iş parçacığı tarafından görülmesinin garanti edilmediğinin farkında değildir . Bunun ortak bir uygulaması:

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}

Sürece durağı olarak değil uçucu ya setStopve runolmayan senkronize bu işe garanti edilmez. Bu hata, özellikle% 99,999'da olduğu gibi şeytani bir şeydir, çünkü okuyucu iş parçacığı sonunda değişikliği görecektir - ancak ne kadar sürede gördüğünü bilmiyoruz.


9
Bunun en iyi çözümü stop örneği değişkenini AtomicBoolean yapmaktır. Sizi JMM sorunlarından korurken, kalıcı olmayan tüm sorunları çözer.
Kirk Wylie

39
'Birkaç dakika' dan daha kötü - ASLA göremezsiniz. Bellek Modeli altında, JVM'nin while (! Stop) iken while (true) 'a optimizasyon yapmasına izin verilir ve daha sonra ıslatılırsınız. Bu, yalnızca bazı VM'lerde, yalnızca sunucu modunda, yalnızca JVM, döngü x yinelemelerinden vb. Sonra yeniden derlendiğinde gerçekleşebilir.
Cowan

2
Neden AtomicBoolean'ı uçucu boolean üzerinde kullanmak istersiniz? Sürüm 1.4+ için geliştiriyorum, bu yüzden sadece uçucu beyan ile herhangi bir tuzak var mı?
Havuz

2
Nick, bence bunun nedeni atom CAS'ın genellikle uçucu olmaktan bile daha hızlı olması. Java 5. yılında olduğu gibi güçlü bellek bariyer garantileri var değil 1.4 uçucu olarak senkronize kullanmak için size 1.4 tek güvenli seçenek IMHO geliştiriyorsanız edilir
Kutzi

5
@Thomas: Bunun nedeni Java bellek modeli. Bunu ayrıntılı olarak bilmek istiyorsanız, okumalısınız (Brian Goetz tarafından Pratikte Java Eşzamanlılığı bunu iyi açıklar). Kısacası: bellek senkronizasyonu anahtar kelimeleri / yapıları (uçucu, senkronize, AtomicXyz gibi, aynı zamanda bir İş Parçacığı bittiğinde) kullanmadığınız sürece, bir İş Parçacığının farklı bir iş parçacığı tarafından yapılan herhangi bir alanda yapılan değişiklikleri görmek için hiçbir garantisi yoktur
Kutzi

179

Benim en acı verici eşzamanlılık sorunum iki farklı açık kaynak kütüphanesi böyle bir şey yaptığında ortaya çıktı :

private static final String LOCK = "LOCK";  // use matching strings 
                                            // in two different libraries

public doSomestuff() {
   synchronized(LOCK) {
       this.work();
   }
}

İlk bakışta, bu oldukça önemsiz bir senkronizasyon örneğine benziyor. Ancak; Dizeler Java'da staj olduğundan , değişmez dize "LOCK"aynı örnek olarak ortaya çıkar java.lang.String(birbirlerinden tamamen farklı olsalar bile) Sonuç açıkça kötüdür.


63
Bu özel statik son tercih nedenlerinden biridir Object LOCK = new Object ();
Andrzej Doyle

17
I love it - oh, bu kötü :)
Thorbjørn Ravn Andersen

7
Bu Java Puzzlers 2 için iyi bir tanesidir
Dov Wasserman

12
Aslında ... derleyicinin bir String üzerinde senkronize etmenize izin vermeyi reddetmesini gerçekten istiyor. String interning verildiğinde, bunun "iyi bir şey (tm)" olacağı hiçbir durum yoktur.
Jared

3
@Jared: "dize staj edilene kadar" hiçbir anlam ifade etmiyor. Teller sihirli bir şekilde "interned" olmaz. String.intern (), belirtilen String'in standart örneğine sahip olmadığınız sürece farklı bir nesne döndürür. Ayrıca, tüm gerçek dizeler ve dize değerli sabit ifadeler stajyerdir. Her zaman. JLS'nin String.intern () ve §3.10.5 belgelerine bakın.
Laurence Gonsalves

65

Klasik sorunlardan biri, senkronize ederken senkronize ettiğiniz nesneyi değiştirmektir:

synchronized(foo) {
  foo = ...
}

Diğer eşzamanlı iş parçacıkları daha sonra farklı bir nesne üzerinde eşitlenir ve bu blok beklediğiniz karşılıklı dışlamayı sağlamaz.


19
"Nihai olmayan alanda yararlı semantiğe sahip olması muhtemel olmayan senkronizasyon" adı verilen bir IDEA incelemesi vardır. Çok hoş.
Jen

8
Ha ... şimdi bu bir işkence açıklaması. "yararlı semantiğe sahip olma olasılığı düşük" daha iyi "büyük olasılıkla bozuk" olarak tanımlanabilir. :)
Alex Miller

Bence bu onun ReadWriteLock vardı Acı Java oldu. Neyse ki şimdi java.util.concurrency.locks var ve Doug biraz daha topun üzerinde.
Tom Hawtin - tackline

Ben de sık sık bu sorunu gördüm. Bu konuda yalnızca son nesnelerle senkronize edin. FindBugs ve diğ. yardım, evet.
gimpf

Bu sadece görevlendirme sırasında bir sorun mu? (@Alex Miller'ın aşağıdaki Haritalı örneğine bakın) Bu harita örneğinde de aynı sorun olur mu?
Alex Beardsley

50

Sık karşılaşılan bir sorun, Takvim ve SimpleDateFormat gibi sınıfları eşitlemeden birden çok iş parçacığından (genellikle statik bir değişkende önbelleğe alarak) kullanmaktır. Bu sınıflar iş parçacığı için güvenli değildir, bu nedenle çok iş parçacıklı erişim sonuçta tutarsız durumla garip sorunlara neden olur.


Bazı sürümlerinde bu hatayı içeren açık kaynaklı bir proje biliyor musunuz? Gerçek dünya yazılımında bu hatanın somut örneklerini arıyorum.
yeniden programcı

48

Özellikle yineleme veya çoklu işlemler sırasında döndürülen nesneler üzerinde düzgün senkronizeCollections.synchronizedXXX() edilmemesi:

Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

...

if(!map.containsKey("foo"))
    map.put("foo", "bar");

Bu yanlış . Tek işlem olmasına rağmen synchronized, çağırma arasındaki haritanın durumu containsve putbaşka bir evre tarafından değiştirilebilir. Olmalı:

synchronized(map) {
    if(!map.containsKey("foo"))
        map.put("foo", "bar");
}

Veya bir ConcurrentMapuygulama ile:

map.putIfAbsent("foo", "bar");

6
Ya da daha iyisi, bir ConcurrentHashMap ve putIfAbsent kullanın.
Tom Hawtin - tackline

47

Çift Kontrollü Kilitleme. Genel olarak.

BEA'da çalışırken yaşadığım sorunları öğrenmeye başladığım paradigma, insanların bir singletonu şu şekilde kontrol edeceğidir:

public Class MySingleton {
  private static MySingleton s_instance;
  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) { s_instance = new MySingleton(); }
    }
    return s_instance;
  }
}

Bu asla işe yaramaz, çünkü senkronize edilmiş bloğa başka bir iş parçacığı girmiş olabilir ve s_instance artık null değildir. Böylece doğal değişim bunu yapmaktır:

  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) {
        if(s_instance == null) s_instance = new MySingleton();
      }
    }
    return s_instance;
  }

Java Bellek Modeli bunu desteklemediğinden bu da işe yaramaz. Çalışması için s_instance değişkenini deklare etmeniz gerekir ve o zaman bile sadece Java 5 üzerinde çalışır.

Java Bellek Modeli'nin karmaşıklıklarına aşina olmayan insanlar bunu her zaman berbat eder .


7
Enum singleton modeli tüm bu sorunları çözer (Josh Bloch'un bu konudaki yorumlarına bakın). Varlığının bilgisi Java programcıları arasında daha yaygın olmalıdır.
Robin

Hala bir singletonun tembel başlatılmasının gerçekten uygun olduğu tek bir vakaya rastlamadım. Ve eğer öyleyse, yöntemi senkronize edilmiş olarak beyan edin.
Dov Wasserman

3
Singleton sınıflarının tembel başlatılması için kullandığım şey bu. Ayrıca java tarafından dolaylı olarak garanti edildiği için senkronizasyon gerekmez. sınıf Foo {statik sınıf Tutucu {statik Foo foo = yeni Foo (); } statik Foo getInstance () {dönüş Holder.foo; }}
Irfan Zulfiqar

Irfan, buna Pugh'un yöntemi deniyor, hatırladığım kadarıyla
Chris R

@Robin, sadece statik bir başlatıcı kullanmak daha kolay değil mi? Bunların her zaman senkronize çalışacağı garanti edilir.
matt b

37

Muhtemelen tam olarak ne istediğinizi olmasa da, karşılaştığım en sık eşzamanlılık sorunu (muhtemelen normal tek iş parçacıklı kodda geldiği için)

java.util.ConcurrentModificationException

gibi şeylerin neden olduğu:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }

Hayır, aradığım şey bu. Teşekkürler!
Alex Miller

30

Senkronize edilmiş koleksiyonların gerçekte olduğundan daha fazla koruma sağladığını düşünmek kolay olabilir ve aramalar arasındaki kilidi tutmayı unutmayın. Bu hatayı birkaç kez gördüm:

 List<String> l = Collections.synchronizedList(new ArrayList<String>());
 String[] s = l.toArray(new String[l.size()]);

Örneğin, yukarıdaki ikinci satırda, toArray()ve size()yöntemlerinin her ikisi de kendi başlarına iş parçacığı açısından güvenlidir, ancak , ve size()öğesinden ayrı olarak değerlendirilir toArray()ve Listedeki kilit bu iki çağrı arasında tutulmaz.

Bu kodu, öğeleri listeden aynı anda kaldıran başka bir iş parçacığıyla çalıştırırsanız , er ya da geç String[], listedeki tüm öğeleri tutmak için gerekenden daha büyük ve kuyrukta null değerleri olan yeni bir döndürme ile sonuçlanırsınız. Listeye iki yöntem çağrısının tek bir kod satırında gerçekleştiği için bunun bir şekilde atomik bir işlem olduğunu düşünmek kolaydır, ancak değildir.


5
iyi örnek. Sanırım bunu daha genel olarak "atomik işlemlerin bileşimi atomik değil" diye tebeşirleyeceğim. (Başka bir basit örnek için geçici alan ++ 'ya bakınız)
Alex Miller

29

Çalıştığım yerde gördüğümüz en yaygın hata, programcıların EDT'de sunucu çağrıları gibi uzun işlemler gerçekleştirmesi, GUI'yi birkaç saniyeliğine kilitlemesi ve uygulamanın yanıt vermemesidir.


Keşke bu cevaplardan biri için birden fazla puan verebilirdim
Epaga

2
EDT = Olay Gönderme İş Parçacığı
mjj1409

28

Bir döngüde wait () (veya Condition.await ()) öğesinin unutulması, bekleme koşulunun gerçekten doğru olup olmadığını kontrol etme. Bu olmadan, sahte wait () uyandırma hataları böcek içine koşmak. Kanonik kullanım:

 synchronized (obj) {
     while (<condition does not hold>) {
         obj.wait();
     }
     // do stuff based on condition being true
 }

26

Başka bir yaygın hata, kötü istisna işlemedir. Bir arka plan iş parçacığı bir istisna atarsa, düzgün işlemezseniz yığın izini hiç göremeyebilirsiniz. Veya arka plan göreviniz çalışmayı durdurur ve istisnayı işleyemediğiniz için bir daha asla başlamaz.


Evet, ve şimdi işleyicileri ile başa çıkmak için iyi araçlar var.
Alex Miller

3
Bunu daha ayrıntılı olarak açıklayan makalelere veya referanslara bağlantılar gönderebilir misiniz?
Abhijeet Kashnia

22

Brian Goetz ile bir ders getteralana kadar, senkronize edilmiş bir mutasyona uğramış özel bir alanın senkronize setteredilmesinin , güncellenmiş değeri döndüreceği asla garanti edilemezdi. Yalnızca bir değişken her iki okumada VE yazarken senkronize blok tarafından korunduğunda , değişkenin en son değerinin garantisini alırsınız.

public class SomeClass{
    private Integer thing = 1;

    public synchronized void setThing(Integer thing)
        this.thing = thing;
    }

    /**
     * This may return 1 forever and ever no matter what is set
     * because the read is not synched
     */
    public Integer getThing(){
        return thing;  
    }
}

5
Daha sonraki JVM'lerde (1.5 ve ileri, sanırım), uçucu kullanımı da bunu düzeltir.
James Schek

2
Şart değil. uçucu size en son değeri verir, böylece sonsuza kadar 1'in geri dönmesini önler, ancak kilitleme sağlamaz. Onun yakın, ama tamamen aynı değil.
John Russell

1
@JohnRussell Uçucu bir ilişkinin daha önce gerçekleşmesini garanti ettiğini düşündüm. "kilitleme" değil mi? Msgstr "Değişken bir değişkene yazma (§8.3.1.4) v, v'nin sonraki tüm okumalarıyla herhangi bir iş parçacığı tarafından senkronize edilir (daha sonra senkronizasyon sırasına göre tanımlanır)."
Shawn

15

Tek iş parçacıklı kod yazdığınızı düşünün, ancak değişebilir statikler kullanın (tektonlar dahil). Açıkçası konu başlıkları arasında paylaşılacaklar. Bu şaşırtıcı bir şekilde sık sık olur.


3
Evet kesinlikle! Değişken statikler iplik hapsini bozar. Şaşırtıcı bir şekilde, JCIP veya CPJ'de bu tuzak hakkında hiçbir şey bulamadım.
Julien Chastang

Umarım bu eşzamanlı programlama yapan insanlar için açıktır. İplik güvenliğini kontrol eden ilk yer küresel devlet olmalıdır.
gtrak

1
@Gary Thing, eşzamanlı programlama yaptıklarını düşünmüyorlar.
Tom Hawtin - taktik hattı

15

Senkronize blokların içinden rastgele yöntem çağrıları yapılmamalıdır.

Dave Ray ilk cevabında buna değindi ve aslında aynı zamanda senkronize edilmiş bir yöntemden dinleyicilere çağrı yapma yöntemleri ile ilgili bir çıkmaza da rastladım. Bence daha genel bir ders yöntem çağrıları senkronize bir blok içinde "vahşi içine" yapılmaması gerektiğidir - çağrının uzun süre çalışıp çalışmayacağı, çıkma veya başka bir sonuçla sonuçlanacağına dair hiçbir fikriniz yok.

Bu durumda ve genellikle genel olarak çözüm, kodun kritik bir özel bölümünü korumak için senkronize bloğun kapsamını azaltmaktı .

Ayrıca, dinleyici Koleksiyonuna senkronize edilmiş bir bloğun dışında eriştiğimiz için, onu bir kopya üzerine yazma Koleksiyonu olarak değiştirdik. Ya da sadece Koleksiyonun savunma amaçlı bir kopyasını oluşturabilirdik. Mesele şu ki, bilinmeyen nesneler koleksiyonuna güvenli bir şekilde erişmek için genellikle alternatifler vardır.


13

Karşılaştığım en son Concurrency ile ilgili hata, yapıcısında bir ExecutorService oluşturan bir nesneydi, ancak nesneye artık başvurulmadığında, ExecutorService'i asla kapatmamıştı. Böylece, birkaç hafta boyunca binlerce iş parçacığı sızdı ve sonunda sistemin çökmesine neden oldu. (Teknik olarak çökmedi, ancak çalışmaya devam ederken düzgün çalışmayı bıraktı.)

Teknik olarak, bunun bir eşzamanlılık sorunu olmadığını, ancak java.util.concurrency kütüphanelerinin kullanımı ile ilgili bir sorun olduğunu düşünüyorum.


11

Dengesiz senkronizasyon, özellikle Haritalar'a karşı, oldukça yaygın bir sorun gibi görünüyor. Birçok kişi Harita üzerinde senkronizasyonun bir ConcurrentMap değil, bir HashMap dediği) ve get üzerinde senkronize olmamanın yeterli olduğuna inanır. Ancak bu yeniden hash işlemi sırasında sonsuz bir döngüye yol açabilir.

Ancak aynı sorun (kısmi senkronizasyon), okuma ve yazma durumlarını paylaştığınız her yerde oluşabilir.


11

Her istek tarafından ayarlanacak değişken alanlar olduğunda Servlets ile bir eşzamanlılık sorunuyla karşılaştım. Ancak, tüm istek için yalnızca bir sunucu uygulaması örneği vardır, bu nedenle bu, tek bir kullanıcı ortamında mükemmel bir şekilde çalıştı, ancak birden fazla kullanıcı sunucu uygulaması beklenmedik şekilde sonuç verdi.

public class MyServlet implements Servlet{
    private Object something;

    public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException{
        this.something = request.getAttribute("something");
        doSomething();
    }

    private void doSomething(){
        this.something ...
    }
}

10

Tam olarak bir hata değil, en kötü günah, başkalarının kullanmayı düşündüğünüz bir kitaplık sağlamaktır, ancak hangi sınıfların / yöntemlerin iş parçacığı için güvenli olduğunu ve hangilerinin yalnızca tek bir iş parçacığından çağrılması gerektiğini belirtmemektedir.

Goetz kitabında açıklanan eşzamanlılık ek açıklamalarından (örneğin @ThreadSafe, @GuardedBy vb.) Daha fazla kişi yararlanmalıdır.


9

En büyük sorunum hep kilitlenmelerdi, özellikle de bir kilitle ateşlenen dinleyicilerin neden olduğu. Bu durumlarda, iki iplik arasında ters kilitleme elde etmek gerçekten kolaydır. Benim durumumda, bir iş parçacığında çalışan bir simülasyon ile UI iş parçacığında çalışan simülasyonun görselleştirilmesi arasında.

EDIT: Ayrı cevap için ikinci bölüm taşındı.


Sonuncuyu ayrı bir cevaba bölebilir misiniz? Her yazı için 1 tutalım. Bunlar gerçekten çok iyi.
Alex Miller

9

Bir sınıfın yapıcısında bir iş parçacığının başlatılması sorunludur. Sınıf genişletilirse, alt sınıf yapıcısı yürütülmeden önce iş parçacığı başlatılabilir .


8

Paylaşılan veri yapılarında değiştirilebilir sınıflar

Thread1:
    Person p = new Person("John");
    sharedMap.put("Key", p);
    assert(p.getName().equals("John");  // sometimes passes, sometimes fails

Thread2:
    Person p = sharedMap.get("Key");
    p.setName("Alfonso");

Bu olduğunda, kod bu basitleştirilmiş örnekten çok daha karmaşıktır. Hatayı çoğaltmak, bulmak ve düzeltmek zordur. Belli sınıfları değişmez ve belirli veri yapılarını sadece değişmez nesneleri tutmak olarak işaretleyebilirsek belki önlenebilir.


8

Bir dize değişmez değeri veya bir dize değişmez değeri tarafından tanımlanan sabit üzerinde eşitleme (potansiyel olarak) dize değişmez değeri sabitlendiğinden ve aynı dize değişmez değeri kullanılarak JVM'deki başka bir kişi tarafından paylaşılacağı bir sorundur. Bu sorunun uygulama sunucuları ve diğer "kapsayıcı" senaryolarda geldi biliyorum.

Misal:

private static final String SOMETHING = "foo";

synchronized(SOMETHING) {
   //
}

Bu durumda, kilitlemek için "foo" dizesini kullanan herkes aynı kilidi paylaşır.


Potansiyel olarak kilitli. Sorun şu ki, WHEN Dizeleri stajyer olduğunda semantik tanımsız (veya IMNSHO, az tanımlanmış). Derleme zamanı sabiti "foo" interned, bir ağ arayüzünden gelen "foo" sadece bunu yaparsanız stajyer.
Kirk Wylie

Doğru, bu yüzden özellikle sabitlenmesi garanti edilen değişmez bir dize sabiti kullandım.
Alex Miller

8

Gelecekte Java ile ilgili asıl sorunun inşaatçılar için görünürlük garantileri olacağına inanıyorum. Örneğin, aşağıdaki sınıfı oluşturursanız

class MyClass {
    public int a = 1;
}

ve sonra MyClass'ın özelliğini başka bir evreden okudum, JavaVM'nin uygulamasına ve ruh haline bağlı olarak MyClass.a 0 veya 1 olabilir. Bugün 'a' 1 olma şansı çok yüksek. Ancak gelecekteki NUMA makinelerinde bu farklı olabilir. Birçok insan bunun farkında değildir ve başlatma aşaması sırasında çoklu iplik geçirmeyi önemsemeleri gerekmediğine inanmaktadır.


Bunu biraz şaşırtıcı buluyorum, ama akıllı bir züppe Tim olduğunu biliyorum, bu yüzden referans olmadan alacağım. :) Ancak, eğer bir final olsaydı, bu bir endişe olmaz, değil mi? O zaman inşaat sırasında son donma semantiği ile bağlı olacak?
Alex Miller

JMM'de hala beni şaşırtan şeyler buluyorum, bu yüzden bana güvenmem, ama bundan eminim. Ayrıca bkz . Cs.umd.edu/~pugh/java/memoryModel/… . Alan son olsaydı sorun olmazdı, başlangıç ​​aşamasından sonra görünür olurdu.
Tim Jansen

2
Yeni oluşturulmuş örneğin başvurusu, kurucu geri dönmeden / bitirmeden önce kullanılıyorsa, bu yalnızca bir sorundur. Örneğin, sınıf bir ortak havuzda inşaat sırasında kendini kaydeder ve diğer iş parçacıkları buna erişmeye başlar.
09:15

3
MyClass.a statik erişimi belirtir ve 'a', MyClass'ın statik bir üyesi değildir. Bunun dışında, 'ReneS' belirttiği gibi, bu sadece tamamlanmamış nesneye yapılan bir başvuru sızdırılırsa, örneğin yapıcıdaki bazı harici haritalara 'this' eklemek gibi bir problemdir.
Markus Jevring

7

Sıklıkla yaptığım en saçma hata, bir nesneye bildirme () veya wait () öğesini çağırmadan önce senkronize etmeyi unutmaktır.


8
Çoğu eşzamanlılık sorununun aksine, bu bulmak kolay değil mi? En azından burada bir IllegalMonitorStateException alıyorsunuz ...
Outlaw Programmer

Neyse ki bulmak çok kolay ... ama yine de zamanımı olması gerekenden daha fazla boşa harcayan aptalca bir hata :)
Dave Ray

7

Muteks olarak yerel bir "yeni Object ()" kullanma.

synchronized (new Object())
{
    System.out.println("sdfs");
}

Bu işe yaramaz.


2
Bu muhtemelen işe yaramaz, ancak senkronizasyon eylemi bazı ilginç şeyler yapar ... Kesinlikle her seferinde yeni bir Nesne yaratmak tam bir israftır.
AĞAÇ

4
Yararsız değil. Kilitsiz hafıza engeli.
David Roussel

1
@David: tek sorun - jvm bu kilidi tamamen kaldırarak optimize edebilir
yetanothercoder

@insighter Fikrinizin paylaşıldığını görüyorum ibm.com/developerworks/java/library/j-jtp10185/index.html Memoery bariyerinizin ne zaman senkronize olacağını bilmediğiniz için, bunun aptalca bir şey olduğunu kabul ediyorum. sadece bunun daha fazlasını yapmadığını işaret ediyordu.
David Roussel

7

Başka bir yaygın 'eşzamanlılık' sorunu da, gerekli olmadığında senkronize kod kullanmaktır. Örneğin hala StringBufferveya hatta java.util.Vector(yöntem yerel değişkenleri olarak) kullanan programcılar görüyorum .


1
Bu bir sorun değil, gereksizdir, çünkü JVM'ye verileri global belleğe senkronize ettiğini söyler ve bu nedenle çoklu cpus üzerinde kötü bir şekilde çalışabilir, hiç kimse senkronizasyon bloğunu eşzamanlı olarak kullanmaz.
09:00

6

Kilit korumalı ancak art arda erişilen birden fazla nesne. Kilitlerin farklı kodlarda farklı kodlarla elde edildiği ve kilitlenmeyle sonuçlandığı birkaç durumla karşılaştık.


5

thisİç sınıftaki thisdış sınıfın olmadığını fark etmemek . Genellikle anonim bir iç sınıfta uygular Runnable. Temel sorun, senkronizasyonun tüm Objects'nin bir parçası olması nedeniyle etkin bir statik tip kontrolü olmamasıdır. Bunu usenet üzerinde en az iki kez gördüm ve Brian Goetz'z Uygulamada Java Eşzamanlılığı'nda da görünüyor.

BGGA kapakları bundan dolayı zarar görmez this, çünkü kapatma için hiçbir şey yoktur ( thisdış sınıfa başvurur ). thisNesne olmayanları kilit olarak kullanırsanız , bu sorun ve diğerlerinin etrafından dolanır.


3

Kilitleme için statik değişken gibi global bir nesnenin kullanılması.

Bu, çekişme nedeniyle çok kötü performansa yol açar.


Bazen, bazen değil. Bu kadar kolay olsaydı ...
gimpf

Diş açmanın verilen sorun için performansı artırmaya yardımcı olduğu varsayılarak, birden fazla iş parçacığı kilit tarafından korunan koda erişir erişmez performansı her zaman düşürür.
kohlerm

3

Honesly? Gelişinden önce java.util.concurrent, rutin olarak karşılaştığım en yaygın sorun "iş parçacığı" olarak adlandırdığım şeydi: Eşzamanlılık için iş parçacığı kullanan, ancak bunların çoğunu ortaya çıkaran ve daralmaya neden olan uygulamalar.


Java.util.concurrent kullanılabilir olduğundan daha fazla sorunla karşılaştığınızı mı ima ediyorsunuz ?
Andrzej Doyle
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.