Java nasıl çalışır

Konu seç, kod yaz ve içeride ne olduğunu adım adım gör.

Memory

Collection'lar

Concurrency

Dil ve JVM

Konular

Thread'ler

Race condition: count++

Her thread'in kendi stack'i vardır, heap ise ortaktır. count heap'te, r stack'tedir.

count++ tek işlem değildir: oku, artır, yaz. İki thread aynı değeri okursa biri diğerinin sonucunun üstüne yazar.

Sonraki düğmesi hazır sırayı gösterir. Thread düğmeleriyle sırayı kendin seç: hangi sırada kayıp olmaz?

synchronized

synchronized bir object'in monitor lock'unu alır. Aynı lock'u aynı anda yalnızca bir thread tutabilir, diğeri BLOCKED olur.

Şimdi thread B'yi A'nın ortasına sok: B ilerleyemez, bu yüzden üç adım birlikte çalışır.

Lock görünürlüğü de sağlar: lock'u alan thread önceki sahibin yazdıklarını görür. Bedeli beklemedir, lock'u mümkün olduğunca kısa tut.

volatile count++'ı düzeltmez

volatile her okumanın en son yazılan değeri görmesini sağlar. Ama oku, artır, yaz yine üç ayrı adımdır.

Farka bak: aynı sıra, aynı kayıp. volatile atomicity vermez.

volatile bir thread'in yazıp diğerlerinin okuduğu durumlar içindir: sonraki bölümlerdeki running flag'i gibi.

CAS ve AtomicInteger

AtomicInteger lock kullanmaz. CAS, yani compare-and-swap, hardware'in tek adımda yaptığı iştir: değer beklediğim gibiyse yenisini yaz, değilse hiçbir şey yapma.

Başarısız olan thread beklemez, yeniden okuyup dener. Thread'ler BLOCKED olmaz.

Yoğun rekabette çok tekrar olabilir. Çok yazılan sayaç için LongAdder da vardır.

Deadlock

Thread A a'yı, B b'yi alır. Sonra A b'yi, B a'yı ister. İkisi de sonsuza kadar bekler, Java bunu kendi çözmez.

En basit çözüm: tüm thread'ler lock'ları aynı sırada alsın. Düğmeyle sırayı değiştir ve yeniden çalıştır.

Gerçek programda jstack deadlock'u bulup gösterir.

Görünürlük: volatile flag

Bir thread'in yazdığını diğeri ne zaman görür? Senkronizasyon yoksa Java garanti vermez.

Bu döngüde worker running değerini okur. JIT değerin değişmediğini varsayıp yeniden okumayabilir, thread sonsuza kadar döner.

volatile, synchronized ve Thread.start/join happens-before oluşturur, yani görünürlüğü garanti eder.

Thread durumları

Thread.getState() altı değerden birini döndürür. Thread dump okurken en çok gereken tablo budur.

Tuzak: RUNNABLE "şu an CPU'da" demek değildir. I/O bekleyen thread de çoğu zaman RUNNABLE görünür.