Sobes.tech
Middle

Java'da synchronized blok nedir ve kullanırken hangi sorunlar ortaya çıkabilir?

sobes.tech yapay zeka

AI'dan gelen yanıt

Java'da synchronized bloğu, birden fazla thread arasında ortak kaynağa erişimi senkronize etmek için kullanılır. Bu, yalnızca bir thread'in herhangi bir zamanda bloğun içindeki kodu çalıştırabileceğini garanti eder.

synchronized bloğunun yapısı:

synchronized (nesne_kilidi) {
    // Kritik kod bölgesi
    // Ortak kaynak üzerinde işlemler
}
  • nesne_kilidi: Herhangi bir nesne, monitör (kilit) olarak hizmet eder. Aynı nesne kilidi ile synchronized bloğuna girmeye çalışan thread'ler, mevcut thread çıkana kadar engellenir.

synchronized kullanırken ortaya çıkabilecek sorunlar:

  • Ölümlü kilit (Deadlock): İki veya daha fazla thread, diğer thread'ler tarafından tutulmakta olan kaynakların serbest bırakılmasını bekler ve bu da programın durmasına neden olur. Bu, thread'lerin farklı sıralarda kilitleri almaya çalışması durumunda olabilir.
  • Performans düşüşü: Senkronizasyon, diğer thread'lerin monitöre erişimini engeller ve bu da paralel uygulamaların yavaşlamasına neden olabilir.
  • Bazı durumlara uygulanamazlık: synchronized bloğu, münhasır erişim sağlar. Bazı durumlarda, daha esnek erişim yönetimi gerekebilir (örneğin, çoklu thread'ler tarafından okuma, tek thread tarafından yazma).
  • Hata ayıklamada zorluk: Senkronizasyon sorunları, fark edilmesi ve yeniden üretilmesi zor olabilir.

Ölümlü kilit örneği:

class Resource {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1(Resource other) {
        synchronized (lock1) {
            try {
                Thread.sleep(100); // İşlem simülasyonu
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " lock1'i edindi");
            synchronized (other.lock2) {
                System.out.println(Thread.currentThread().getName() + " diğer kaynağın lock2'sini edindi");
            }
        }
    }

    public void method2(Resource other) {
        synchronized (lock2) {
             try {
                Thread.sleep(100); // İşlem simülasyonu
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " lock2'yi edindi");
            synchronized (other.lock1) {
                System.out.println(Thread.currentThread().getName() + " diğer kaynağın lock1'ini edindi");
            }
        }
    }
}

public class DeadlockExample {
    public static void main(String[] args) {
        Resource r1 = new Resource();
        Resource r2 = new Resource();

        new Thread(() -> r1.method1(r2), "Thread-1").start();
        new Thread(() -> r2.method2(r1), "Thread-2").start();
    }
}

Bu örnekte, Thread-1 lock1'i r1 üzerinde ve sonra lock2'yi r2 üzerinde almaya çalışır. Thread-2 ise lock2'yi r2 üzerinde ve sonra lock1'i r1 üzerinde almaya çalışır. Eğer her ikisi de ilk kilidi aynı anda alırsa, bir ölümlü kilit oluşur.