Apa masalah konkurensi yang paling sering Anda temui di Jawa? [Tutup]

191

Ini adalah polling tentang masalah konkurensi umum di Jawa. Contoh mungkin kebuntuan klasik atau kondisi balapan atau mungkin bug threading EDT di Swing. Saya tertarik baik dalam berbagai kemungkinan masalah tetapi juga dalam masalah apa yang paling umum. Jadi, silakan tinggalkan satu jawaban spesifik bug konkurensi Java per komentar dan berikan suara jika Anda melihat yang Anda temui.

Alex Miller
sumber
16
Kenapa ini ditutup? Ini berguna baik bagi pemrogram lain yang meminta konkurensi di Jawa, dan untuk mengetahui kelas cacat konkurensi apa yang paling banyak diamati oleh pengembang Java lainnya.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
@ Longpoke Pesan penutupan menjelaskan mengapa ditutup. Ini bukan pertanyaan dengan jawaban "benar" yang spesifik, ini lebih merupakan pertanyaan jajak pendapat / daftar. Dan Stack Overflow tidak bermaksud meng-host pertanyaan semacam ini. Jika Anda tidak setuju dengan kebijakan itu, Anda mungkin ingin mendiskusikannya dengan meta .
Andrzej Doyle
7
Saya kira komunitas tidak setuju karena artikel ini mendapatkan 100+ tampilan / hari! Saya merasa sangat berguna karena saya terlibat dalam pengembangan alat analisis statis yang dirancang khusus untuk memperbaiki masalah konkurensi contemplateltd.com/threadsafe . Memiliki bank yang memiliki masalah konkurensi yang umum dijumpai sangat bagus untuk menguji dan meningkatkan ThreadSafe.
Craig Manson
Daftar periksa ulasan kode untuk Java Concurrency mencerna sebagian besar jebakan yang disebutkan dalam jawaban untuk pertanyaan ini dalam bentuk yang nyaman untuk ulasan kode sehari-hari.
leventov

Jawaban:

125

Masalah konkurensi paling umum yang pernah saya lihat, adalah tidak menyadari bahwa bidang yang ditulis oleh satu utas tidak dijamin dilihat oleh utas yang berbeda. Aplikasi umum ini:

class MyThread extends Thread {
  private boolean stop = false;

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

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

Selama berhenti tidak stabil atau setStopdan runtidak disinkronkan ini tidak dijamin untuk bekerja. Kesalahan ini terutama jahat karena pada 99,999% itu tidak masalah dalam praktik karena pembaca akhirnya akan melihat perubahan - tetapi kita tidak tahu seberapa cepat dia melihatnya.

Kutzi
sumber
9
Solusi yang bagus untuk ini adalah membuat stop instance variable menjadi AtomicBoolean. Ini memecahkan semua masalah non-volatile, sambil melindungi Anda dari masalah JMM.
Kirk Wylie
39
Ini lebih buruk daripada 'selama beberapa menit' - Anda mungkin TIDAK PERNAH melihatnya. Di bawah Memory Model, JVM diizinkan untuk mengoptimalkan while (! Stop) menjadi while (true) dan kemudian Anda disemprot. Ini hanya dapat terjadi pada beberapa VM, hanya dalam mode server, hanya ketika JVM mengkompilasi ulang setelah x iterasi loop, dll. Aduh!
Cowan
2
Mengapa Anda ingin menggunakan AtomicBoolean di atas volatile boolean? Saya sedang mengembangkan untuk versi 1.4+, jadi apakah ada jebakan dengan hanya menyatakan volatile?
Pool
2
Nick, saya pikir itu karena CAS atom biasanya lebih cepat daripada volatile. Jika Anda sedang mengembangkan untuk 1,4 pilihan IMHO hanya aman Anda untuk menggunakan disinkronisasi sebagai volatile di 1,4 belum mendapat jaminan penghalang memori yang kuat seperti yang telah di Jawa 5.
Kutzi
5
@ Thomas: itu karena model memori Java. Anda harus membacanya, jika Anda ingin mengetahuinya secara terperinci (Java Concurrency in Practice oleh Brian Goetz menjelaskannya dengan baik, misalnya). Singkatnya: kecuali jika Anda menggunakan kata kunci / konstruksi sinkronisasi memori (seperti volatile, disinkronkan, AtomicXyz, tetapi juga ketika sebuah Thread selesai) satu Thread tidak memiliki jaminan apa pun untuk melihat perubahan yang dilakukan pada bidang apa pun yang dilakukan oleh thread yang berbeda
Kutzi
178

Saya # 1 yang paling menyakitkan masalah concurrency yang pernah terjadi ketika dua yang berbeda perpustakaan open source melakukan sesuatu seperti ini:

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

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

Sepintas, ini terlihat seperti contoh sinkronisasi yang cukup sepele. Namun; karena String diinternir di Jawa, string literal "LOCK"ternyata menjadi contoh yang sama java.lang.String(meskipun mereka dinyatakan sepenuhnya berbeda satu sama lain.) Hasilnya jelas buruk.

Jared
sumber
62
Ini adalah salah satu alasan mengapa saya lebih suka private static final Object LOCK = new Object ();
Andrzej Doyle
17
Aku menyukainya - oh, ini adalah jahat :)
Thorbjørn Ravn Andersen
7
Itu bagus untuk Java Puzzlers 2.
Dov Wasserman
12
Sebenarnya ... itu benar-benar membuat saya ingin kompiler menolak untuk memungkinkan Anda melakukan sinkronisasi pada String. Diberikan String magang, tidak ada kasus di mana itu akan menjadi "hal yang baik (tm)".
Jared
3
@ Jared: "sampai string diinternir" tidak masuk akal. String tidak secara ajaib "menjadi" diinternir. String.intern () mengembalikan objek yang berbeda, kecuali Anda sudah memiliki instance kanonik dari String yang ditentukan. Juga, semua string literal dan ekspresi konstan bernilai string diinternir. Selalu. Lihat dokumen untuk String.intern () dan §3.10.5 dari JLS.
Laurence Gonsalves
65

Satu masalah klasik adalah mengubah objek yang Anda sinkronkan saat menyinkronkannya:

synchronized(foo) {
  foo = ...
}

Utas bersamaan lainnya kemudian disinkronkan pada objek yang berbeda dan blok ini tidak memberikan pengecualian bersama yang Anda harapkan.

Alex Miller
sumber
19
Ada inspeksi IDEA untuk ini yang disebut "Sinkronisasi pada bidang non-final tidak mungkin memiliki semantik yang berguna". Sangat bagus.
Jen S.
8
Ha ... sekarang itu deskripsi yang tersiksa. "tidak mungkin memiliki semantik yang bermanfaat" bisa lebih baik digambarkan sebagai "kemungkinan besar rusak". :)
Alex Miller
Saya pikir itu adalah Java Pahit yang memiliki ini di ReadWriteLock. Untungnya kita sekarang memiliki java.util.concurrency.locks, dan Doug sedikit lebih tertarik.
Tom Hawtin - tackline
Saya juga sering melihat masalah ini. Hanya menyinkronkan pada objek akhir, dalam hal ini. FindBugs et al. tolong ya
gimpf
Apakah ini hanya masalah selama penugasan? (lihat contoh @Alex Miller di bawah ini dengan Peta) Apakah contoh peta itu memiliki masalah yang sama?
Alex Beardsley
50

Masalah umum adalah menggunakan kelas-kelas seperti Kalender dan SimpleDateFormat dari banyak utas (seringkali dengan menyimpannya dalam variabel statis) tanpa sinkronisasi. Kelas-kelas ini tidak aman thread sehingga akses multi-thread pada akhirnya akan menyebabkan masalah aneh dengan keadaan tidak konsisten.

Alex Miller
sumber
Apakah Anda tahu ada proyek open source yang mengandung bug ini di beberapa versi itu? Saya mencari contoh nyata bug ini dalam perangkat lunak dunia nyata.
Pemrogram ulang
47

Penguncian Ganda. Umumnya.

Paradigma, yang saya mulai pelajari dari masalah ketika saya bekerja di BEA, adalah bahwa orang akan memeriksa singleton dengan cara berikut:

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;
  }
}

Ini tidak pernah berhasil, karena utas lain mungkin telah masuk ke blok yang disinkronkan dan s_instance tidak lagi nol. Jadi perubahan alami adalah membuatnya:

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

Itu juga tidak berhasil, karena Java Memory Model tidak mendukungnya. Anda perlu mendeklarasikan s_instance sebagai volatile untuk membuatnya berfungsi, dan itupun hanya berfungsi di Java 5.

Orang yang tidak terbiasa dengan seluk-beluk Model Memori Java mengacaukan ini sepanjang waktu .

Kirk Wylie
sumber
7
Pola enum singleton memecahkan semua masalah ini (lihat komentar Josh Bloch tentang ini). Pengetahuan tentang keberadaannya harus lebih luas di kalangan programmer Java.
Robin
Saya masih belum menemukan satu kasus di mana inisialisasi malas dari seorang singleton sebenarnya tepat. Dan jika ya, cukup nyatakan metode yang disinkronkan.
Dov Wasserman
3
Inilah yang saya gunakan untuk inisialisasi Lazy kelas Singleton. Juga tidak ada sinkronisasi yang diperlukan karena ini dijamin oleh java secara implisit. class Foo {pemegang kelas statis {static Foo foo = new Foo (); } static Foo getInstance () {return Holder.foo; }}
Irfan Zulfiqar
Irfan, itu disebut metode Pugh, dari apa yang saya ingat
Chris R
@Robin, bukankah lebih mudah menggunakan penginisialisasi statis saja? Itu selalu dijamin untuk menjalankan disinkronkan.
matt b
47

Tidak menyinkronkan dengan benar objek yang dikembalikan oleh Collections.synchronizedXXX(), terutama selama iterasi atau beberapa operasi:

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

...

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

Itu salah . Meskipun ada satu operasi synchronized, keadaan peta antara memohon containsdan putdapat diubah oleh utas lainnya. Harus:

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

Atau dengan ConcurrentMapimplementasi:

map.putIfAbsent("foo", "bar");
Dave Ray
sumber
5
Atau lebih baik, gunakan ConcurrentHashMap dan putIfAbsent.
Tom Hawtin - tackline
37

Meskipun mungkin tidak persis apa yang Anda minta, masalah terkait konkurensi yang paling sering saya temui (mungkin karena muncul dalam kode single-threaded normal) adalah

java.util.ConcurrentModificationException

disebabkan oleh hal-hal seperti:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }
Fabian Steeg
sumber
Tidak, itu benar-benar yang saya cari. Terima kasih!
Alex Miller
30

Mungkin mudah untuk berpikir bahwa koleksi yang disinkronkan memberi Anda lebih banyak perlindungan daripada yang sebenarnya, dan lupa untuk memegang kunci di antara panggilan. Saya telah melihat kesalahan ini beberapa kali:

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

Misalnya, pada baris kedua di atas, metode toArray()dan size()keduanya aman untuk masing-masing thread, tetapi size()dievaluasi secara terpisah dari toArray(), dan kunci pada Daftar tidak ditahan di antara dua panggilan ini.

Jika Anda menjalankan kode ini dengan utas lain secara bersamaan menghapus item dari daftar, cepat atau lambat Anda akan berakhir dengan pengembalian baru String[]yang lebih besar dari yang diperlukan untuk menahan semua elemen dalam daftar, dan memiliki nilai nol di bagian ekor. Sangat mudah untuk berpikir bahwa karena dua metode panggilan ke Daftar terjadi dalam satu baris kode, ini entah bagaimana merupakan operasi atom, tetapi tidak.

Nick
sumber
5
contoh yang baik. Saya pikir saya akan menggunakan ini secara umum sebagai "komposisi operasi atom bukan atom". (Lihat bidang volatile ++ untuk contoh sederhana lainnya)
Alex Miller
29

Bug paling umum yang kita lihat di tempat saya bekerja adalah programmer melakukan operasi panjang, seperti panggilan server, pada EDT, mengunci GUI selama beberapa detik dan membuat aplikasi tidak responsif.

Eric Burke
sumber
salah satu jawaban saya berharap saya bisa memberikan lebih dari satu poin untuk
Epaga
2
EDT = Utas Pengiriman Acara
mjj1409
28

Lupa menunggu () (atau Condition.await ()) dalam satu lingkaran, memeriksa bahwa kondisi menunggu sebenarnya benar. Tanpa ini, Anda mengalami bug dari wake () wakeups palsu. Penggunaan kanonik harus:

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

Bug umum lainnya adalah penanganan pengecualian yang buruk. Ketika utas latar belakang mengeluarkan pengecualian, jika Anda tidak menanganinya dengan benar, Anda mungkin tidak melihat jejak tumpukan sama sekali. Atau mungkin tugas latar belakang Anda berhenti berjalan dan tidak pernah mulai lagi karena Anda gagal menangani pengecualian.

Eric Burke
sumber
Yap, dan ada alat yang baik untuk menangani ini sekarang dengan penangan.
Alex Miller
3
Bisakah Anda memposting tautan ke artikel atau referensi yang menjelaskan hal ini secara lebih rinci?
Abhijeet Kashnia
22

Sampai aku mengambil kelas dengan Brian Goetz saya tidak menyadari bahwa non-disinkronkan getterdari bidang swasta bermutasi melalui disinkronkan setteradalah tidak pernah dijamin untuk mengembalikan nilai diperbarui. Hanya ketika suatu variabel dilindungi oleh blok yang disinkronkan pada kedua tulisan DAN tulisan maka Anda akan mendapatkan jaminan nilai terbaru dari variabel tersebut.

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;  
    }
}
John Russell
sumber
5
Dalam JVM nanti (1,5 dan maju, saya pikir), penggunaan volatile akan memperbaikinya juga.
James Schek
2
Belum tentu. volatile memberi Anda nilai terbaru sehingga mencegah pengembalian 1 selamanya, tetapi tidak memberikan penguncian. Itu dekat, tetapi tidak persis sama.
John Russell
1
@ JohnRussell Saya pikir volatile menjamin hubungan yang terjadi sebelum. bukankah itu "mengunci"? "Sebuah penulisan ke variabel volatil (§8.3.1.4) v menyinkronkan-dengan semua pembacaan v selanjutnya oleh utas apa pun (di mana selanjutnya didefinisikan berdasarkan urutan sinkronisasi)."
Shawn
15

Mengira Anda sedang menulis kode single-threaded, tetapi menggunakan statika yang bisa berubah (termasuk lajang). Jelas mereka akan dibagikan di antara utas. Ini sering terjadi secara mengejutkan.

Tom Hawtin - tackline
sumber
3
Ya memang! Statika yang bisa berubah memecah batasan utas. Anehnya, saya tidak pernah menemukan apa pun tentang jebakan ini di JCiP atau CPJ.
Julien Chastang
Saya berharap ini jelas bagi orang-orang yang melakukan pemrograman bersamaan. Negara global harus menjadi tempat pertama untuk memeriksa keamanan benang.
gtrak
1
@Gary Thing adalah, mereka tidak berpikir bahwa mereka sedang melakukan pemrograman bersamaan.
Tom Hawtin - tackline
15

Panggilan metode sewenang-wenang tidak boleh dilakukan dari dalam blok yang disinkronkan.

Dave Ray menyentuh ini dalam jawaban pertamanya, dan pada kenyataannya saya juga menemui jalan buntu juga berkaitan dengan memohon metode pada pendengar dari dalam metode yang disinkronkan. Saya pikir pelajaran yang lebih umum adalah bahwa pemanggilan metode tidak boleh dibuat "ke alam" dari dalam blok yang disinkronkan - Anda tidak tahu apakah panggilan akan berjalan lama, mengakibatkan kebuntuan, atau apa pun.

Dalam kasus ini, dan biasanya secara umum, solusinya adalah mengurangi ruang lingkup blok yang disinkronkan untuk hanya melindungi bagian kode yang penting secara pribadi .

Juga, karena kami sekarang mengakses Koleksi pendengar di luar blok yang disinkronkan, kami mengubahnya menjadi Koleksi copy-on-write. Atau kita bisa saja membuat salinan Koleksi yang defensif. Intinya, biasanya ada alternatif untuk mengakses Koleksi benda-benda yang tidak dikenal dengan aman.

Scott Bale
sumber
13

Bug yang berhubungan dengan Concurrency terbaru yang saya temui adalah sebuah objek yang dalam konstruktornya menciptakan ExecutorService, tetapi ketika objek tersebut tidak lagi direferensikan, itu tidak pernah mematikan ExecutorService. Jadi, selama beberapa minggu, ribuan utas bocor, akhirnya menyebabkan sistem macet. (Secara teknis, itu tidak crash, tapi itu berhenti berfungsi dengan baik, sambil terus berjalan.)

Secara teknis, saya kira ini bukan masalah konkurensi, tapi ini masalah yang berkaitan dengan penggunaan perpustakaan java.util.concurrency.

Eddie
sumber
11

Sinkronisasi yang tidak seimbang, khususnya terhadap Maps tampaknya menjadi masalah yang cukup umum. Banyak orang percaya bahwa sinkronisasi on menempatkan ke Peta (bukan ConcurrentMap, tapi katakanlah HashMap) dan tidak disinkronkan saat mendapat sudah cukup. Namun ini dapat menyebabkan loop tak terbatas selama re-hash.

Masalah yang sama (sinkronisasi parsial) dapat terjadi di mana saja Anda telah berbagi keadaan dengan membaca dan menulis.

Alex Miller
sumber
11

Saya mengalami masalah konkurensi dengan Servlets, ketika ada bidang yang bisa berubah yang akan diselesaikan oleh setiap permintaan. Tetapi hanya ada satu instance servlet untuk semua permintaan, jadi ini berfungsi dengan baik dalam lingkungan pengguna tunggal tetapi ketika lebih dari satu pengguna meminta hasil servlet yang tidak terduga terjadi.

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 ...
    }
}
Ludwig Wensauer
sumber
10

Bukan bug tetapi, dosa terburuk adalah menyediakan perpustakaan yang Anda maksud orang lain gunakan, tetapi tidak menyatakan kelas / metode mana yang aman untuk thread dan mana yang hanya boleh dipanggil dari satu utas dll.

Lebih banyak orang harus menggunakan penjelasan konkurensi (mis. @ThreadSafe, @GuardedBy dll) yang dijelaskan dalam buku Goetz.

Neil Bartlett
sumber
9

Masalah terbesar saya selalu kebuntuan, terutama disebabkan oleh pendengar yang dipecat dengan kunci dipegang. Dalam kasus ini, sangat mudah untuk mendapatkan penguncian terbalik antara dua utas. Dalam kasus saya, antara simulasi berjalan di satu utas dan visualisasi dari simulasi berjalan di utas UI.

EDIT: Pindah bagian kedua untuk memisahkan jawaban.

Dave Ray
sumber
Bisakah Anda membagi yang terakhir menjadi jawaban yang terpisah? Mari kita tetap 1 per posting. Ini adalah dua yang sangat bagus.
Alex Miller
9

Memulai utas dalam konstruktor suatu kelas bermasalah. Jika kelas diperluas, utas dapat dimulai sebelum konstruktor subkelas dieksekusi.

grayger
sumber
8

Kelas yang dapat diubah dalam struktur data bersama

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");

Ketika ini terjadi, kode jauh lebih kompleks dari contoh sederhana ini. Menggandakan, menemukan, dan memperbaiki bug itu sulit. Mungkin bisa dihindari jika kita bisa menandai kelas tertentu sebagai struktur data yang tidak dapat diubah dan tertentu sebagai hanya memegang objek yang tidak dapat diubah.

Steve McLeod
sumber
8

Sinkronisasi pada string literal atau konstan yang didefinisikan oleh string literal (berpotensi) merupakan masalah karena string literal diinternir dan akan dibagikan oleh siapa pun di JVM menggunakan string literal yang sama. Saya tahu masalah ini telah muncul di server aplikasi dan skenario "wadah" lainnya.

Contoh:

private static final String SOMETHING = "foo";

synchronized(SOMETHING) {
   //
}

Dalam hal ini, siapa pun yang menggunakan string "foo" untuk mengunci berbagi kunci yang sama.

Alex Miller
sumber
Berpotensi terkunci. Masalahnya adalah bahwa semantik pada SAAT Strings diinternir tidak terdefinisi (atau, IMNSHO, underdefined). Konstanta waktu kompiler "foo" diinternir, "foo" yang datang dari antarmuka jaringan hanya diinternir jika Anda membuatnya.
Kirk Wylie
Benar, itu sebabnya saya secara khusus menggunakan konstanta string literal, yang dijamin akan diinternir.
Alex Miller
8

Saya percaya di masa depan masalah utama dengan Java adalah (kurangnya) jaminan visibilitas untuk konstruktor. Misalnya, jika Anda membuat kelas berikut

class MyClass {
    public int a = 1;
}

dan kemudian hanya membaca MyClass ini properti yang dari thread lain, MyClass.a bisa baik 0 atau 1, tergantung pada pelaksanaan dan suasana hati JavaVM ini. Saat ini peluang untuk 'a' menjadi 1 sangat tinggi. Tetapi pada mesin NUMA masa depan ini mungkin berbeda. Banyak orang tidak menyadari hal ini dan percaya bahwa mereka tidak perlu peduli multi-threading selama fase inisialisasi.

Tim Jansen
sumber
Saya menemukan ini agak mengejutkan, tapi saya tahu Anda adalah dude Tim pintar jadi saya akan menerimanya tanpa referensi. :) Namun, jika final, ini tidak akan menjadi masalah, benar? Anda kemudian akan terikat oleh semantik pembekuan akhir selama konstruksi?
Alex Miller
Saya masih menemukan hal-hal di JMM yang mengejutkan saya, jadi saya tidak akan percaya saya, tapi saya cukup yakin tentang ini. Lihat juga cs.umd.edu/~pugh/java/memoryModel/… . Jika bidang itu final, itu tidak akan menjadi masalah, maka itu akan terlihat setelah fase inisialisasi.
Tim Jansen
2
Ini hanya masalah, jika referensi dari instance yang baru dibuat sudah digunakan sebelum konstruktor telah kembali / selesai. Misalnya kelas mendaftar sendiri selama konstruksi di kolam renang umum dan utas lainnya mulai mengaksesnya.
ReneS
3
MyClass.a menunjukkan akses statis, dan 'a' bukan anggota statis MyClass. Selain itu, ini seperti 'ReneS' menyatakan, ini hanya masalah jika referensi ke objek yang tidak selesai bocor, seperti menambahkan 'ini' ke beberapa peta eksternal di konstruktor, misalnya.
Markus Jevring
7

Kesalahan paling bodoh yang sering saya lakukan adalah lupa untuk menyinkronkan sebelum memanggil notify () atau wait () pada suatu objek.

Dave Ray
sumber
8
Tidak seperti kebanyakan masalah konkurensi, bukankah ini mudah ditemukan? Setidaknya Anda mendapatkan IllegalMonitorStateException sini ...
Outlaw Programmer
Untungnya sangat mudah untuk menemukan ... tapi itu masih merupakan kesalahan bodoh yang membuang-buang waktu saya lebih dari yang seharusnya :)
Dave Ray
7

Menggunakan "Objek baru ()" lokal sebagai mutex.

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

Ini tidak berguna.

Ludwig Wensauer
sumber
2
Ini mungkin tidak berguna, tetapi tindakan sinkronisasi sama sekali melakukan beberapa hal menarik ... Tentu saja menciptakan Obyek baru setiap kali adalah sia-sia.
POHON
4
Itu tidak berguna. Itu penghalang memori tanpa kunci.
David Roussel
1
@ David: satu-satunya masalah - jvm dapat mengoptimalkannya dengan menghapus kunci tersebut sama sekali
yetanothercoder
@insight Saya melihat pendapat Anda dibagikan ibm.com/developerworks/java/library/j-jtp10185/index.html Saya setuju bahwa itu hal yang konyol untuk dilakukan, karena Anda tidak tahu kapan penghalang memoery Anda akan disinkronkan, saya hanya menunjukkan bahwa melakukan lebih dari itu tidak ada.
David Roussel
7

Masalah 'konkurensi' lain yang umum adalah menggunakan kode yang disinkronkan ketika tidak diperlukan sama sekali. Sebagai contoh saya masih melihat programmer menggunakan StringBufferatau bahkan java.util.Vector(sebagai metode variabel lokal).

Kutzi
sumber
1
Ini bukan masalah, tetapi tidak perlu, karena ini memberitahu JVM menyinkronkan data dengan memori global dan karena itu mungkin berjalan buruk pada multi-CPU meskipun begitu, tidak ada yang menggunakan blok sinkronisasi secara bersamaan.
ReneS
6

Beberapa objek yang dilindungi kunci tetapi biasanya diakses secara berurutan. Kami telah mengalami beberapa kasus di mana kunci diperoleh oleh kode yang berbeda dalam pesanan yang berbeda, yang mengakibatkan kebuntuan.

Brendan Cashman
sumber
5

Tidak menyadari bahwa thiskelas dalam bukanlah thiskelas luar. Biasanya di kelas batin anonim yang mengimplementasikan Runnable. Masalah mendasarnya adalah karena sinkronisasi adalah bagian dari semua Objects, maka secara efektif tidak ada pemeriksaan tipe statis. Saya telah melihat ini setidaknya dua kali di usenet, dan itu juga muncul di Brian Goetz'z Java Concurrency in Practice.

Penutupan BGGA tidak menderita karena ini tidak ada thisuntuk penutupan ( thisreferensi kelas luar). Jika Anda menggunakan non- thisobjek sebagai kunci maka itu mengatasi masalah ini dan yang lainnya.

Tom Hawtin - tackline
sumber
3

Penggunaan objek global seperti variabel statis untuk mengunci.

Hal ini menyebabkan kinerja yang sangat buruk karena pertikaian.

Kohlerm
sumber
Yah, terkadang, kadang tidak. Jika saja semudah itu ...
Gimpf
Menganggap bahwa threading sama sekali membantu meningkatkan kinerja untuk masalah yang diberikan, itu selalu menurunkan kinerja segera setelah lebih dari satu utas mengakses kode yang dilindungi oleh kunci.
kohlerm
3

Honesly? Sebelum munculnya java.util.concurrent, masalah paling umum yang sering saya temui adalah apa yang saya sebut "meronta-ronta": Aplikasi yang menggunakan utas untuk konkurensi, tetapi menelurkan terlalu banyak dan akhirnya meronta-ronta.

Brian Clapper
sumber
Apakah Anda menyiratkan bahwa Anda mengalami lebih banyak masalah sekarang karena java.util.concurrent tersedia?
Andrzej Doyle