Sitemap
BilgeAdam Teknoloji

BilgeAdam Teknoloji yazılım geliştiricilerinin deneyimlediği makalelerinin bir çatı altında toplandığı tüm yazılım geliştiricilerin faydalanması için oluşturduğu paylaşım sayfasıdır.

Java Concurrency ve Multithreading: Eş Zamanlılık Dünyasına Giriş

5 min readJul 12, 2024

--

Press enter or click to view image in full size

Aynı Anda Birden Fazla Şey Yapabilir misiniz?

Gerçek hayatta aynı anda birden fazla iş yapabiliyor musunuz? Örneğin, aynı anda yemek pişirirken, televizyon izlemek ve çocuklarınızla ilgilenmek? Zor, değil mi? İşte bilgisayar dünyasında da benzer bir problem var: Aynı anda birden fazla işlemi gerçekleştirmek.

Java’da bu sorunu çözmek için iki önemli kavram var: Concurrency (Eşzamanlılık) ve Multithreading (Çoklu İş Parçacığı). Bu yazıda, bu kavramların ne olduğunu, nasıl çalıştığını ve bunları kullanarak nasıl daha verimli uygulamalar geliştirebileceğinizi anlatacağız. Ve evet, eğlenceli ve samimi bir dille!

Concurrency ve Multithreading Nedir?

  • Concurrency (Eşzamanlılık): Bir programın, birden fazla işi aynı anda yapabilmesi yeteneğidir. Bilgisayar, aynı anda birden fazla görevi işler gibi görünür.
  • Multithreading (Çoklu İş Parçacığı): Bir programın, birden fazla iş parçacığı (thread) oluşturup, bu iş parçacıklarının aynı anda çalışmasını sağlar. Her iş parçacığı, programın bağımsız bir parçası gibi çalışır.

Neden Concurrency ve Multithreading?

Gerçek hayatta olduğu gibi, bilgisayar programlarında da aynı anda birden fazla iş yapmanın birçok avantajı vardır:

  1. Performans Artışı: CPU’nun boşta kalmasını engeller ve işlem gücünü maksimum seviyede kullanır.
  2. Daha İyi Kullanıcı Deneyimi: Kullanıcı arayüzü donmaz ve daha akıcı bir deneyim sağlar.
  3. Kaynakların Verimli Kullanımı: İ/O işlemleri gibi uzun süren işlemler beklenirken diğer işlemler devam edebilir.

Temel Kavramlar ve Yapılar

İş Parçacığı (Thread)

Java’da bir iş parçacığı, java.lang.Thread sınıfı veya java.lang.Runnable arayüzü kullanılarak oluşturulabilir.

// Thread sınıfını kullanarak
class MyThread extends Thread {
// Bu metot, iş parçacığı çalıştığında yürütülecek kodu içerir.
public void run() {
System.out.println("Thread çalışıyor.");
}
}

// Ana sınıf ve ana metot
public class Main {
public static void main(String[] args) {
// Yeni bir iş parçacığı oluşturuluyor ve başlatılıyor.
MyThread thread = new MyThread();
thread.start();
}
}

Bu örnekte, MyThread sınıfı Thread sınıfını genişletiyor ve run metodunu override ediyor. Main sınıfında yeni bir MyThread nesnesi oluşturulup başlatılıyor.

// Runnable arayüzünü kullanarak
class MyRunnable implements Runnable {
// Bu metot, iş parçacığı çalıştığında yürütülecek kodu içerir.
public void run() {
System.out.println("Runnable çalışıyor.");
}
}

// Ana sınıf ve ana metot
public class Main {
public static void main(String[] args) {
// Yeni bir iş parçacığı oluşturuluyor ve başlatılıyor.
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}

Bu örnekte, MyRunnable sınıfı Runnable arayüzünü implement ediyor ve run metodunu override ediyor. Main sınıfında yeni bir Thread nesnesi oluşturulup MyRunnable nesnesi ile başlatılıyor.

İş Parçacığı Yönetimi

İş parçacıklarını yönetmek, özellikle büyük ve karmaşık uygulamalarda zor olabilir. Java, bu konuda yardımcı olacak çeşitli araçlar sağlar.

  • Executor Framework: İş parçacıklarını yönetmek için kullanılır. ExecutorService sınıfı, iş parçacıklarını daha verimli bir şekilde yönetir.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// Runnable arayüzünü implement eden sınıf
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable çalışıyor.");
}
}

// Ana sınıf ve ana metot
public class Main {
public static void main(String[] args) {
// ExecutorService ile bir iş parçacığı havuzu oluşturuluyor.
ExecutorService executor = Executors.newFixedThreadPool(10);

// ExecutorService kullanarak iş parçacıkları başlatılıyor.
executor.execute(new MyRunnable());

// ExecutorService kapatılıyor.
executor.shutdown();
}
}

Bu örnekte, ExecutorService kullanarak bir iş parçacığı havuzu oluşturuluyor ve execute metodu ile iş parçacıkları başlatılıyor. Son olarak, shutdown metodu ile havuz kapatılıyor.

Senkronizasyon (Synchronization)

Birden fazla iş parçacığı aynı kaynağa erişmeye çalıştığında, veri tutarsızlıkları ve yarış durumları (race conditions) meydana gelebilir. Bu durumları önlemek için senkronizasyon kullanılır.

// Counter sınıfı, bir sayacı temsil ediyor.
class Counter {
private int count = 0;

// synchronized anahtar kelimesi ile bu metot senkronize ediliyor.
public synchronized void increment() {
count++;
}

// Sayacı döndüren metot
public int getCount() {
return count;
}
}

// Ana sınıf ve ana metot
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();

// Birden fazla iş parçacığı oluşturuluyor ve başlatılıyor.
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

thread1.start();
thread2.start();

try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// Nihai sayacı yazdırıyor.
System.out.println("Final count: " + counter.getCount());
}
}

Bu örnekte, Counter sınıfı bir sayaç içeriyor ve increment metodu senkronize edilerek aynı anda birden fazla iş parçacığının erişiminden kaynaklanan sorunlar önleniyor. İki iş parçacığı oluşturulup başlatılıyor ve her biri sayaç değerini 1000 kez artırıyor. join metodları ile ana iş parçacığı, diğer iş parçacıklarının tamamlanmasını bekliyor ve nihai sayaç değeri yazdırılıyor.

ReentrantLock Kullanımı

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// Banka hesabı sınıfı
class BankAccount {
private int balance = 0;
private Lock lock = new ReentrantLock();

// Para yatırma işlemi, kilitleme kullanılarak senkronize ediliyor.
public void deposit(int amount) {
lock.lock();
try {
balance += amount;
} finally {
lock.unlock();
}
}

// Bakiye döndüren metot
public int getBalance() {
return balance;
}
}

// Ana sınıf ve ana metot
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();

// Para yatırma işlemi gerçekleştiren iş parçacığı
Runnable depositTask = () -> {
for (int i = 0; i < 1000; i++) {
account.deposit(1);
}
};

Thread thread1 = new Thread(depositTask);
Thread thread2 = new Thread(depositTask);

thread1.start();
thread2.start();

try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// Nihai bakiyeyi yazdırıyor.
System.out.println("Final balance: " + account.getBalance());
}
}

Bu örnekte, BankAccount sınıfı bir banka hesabını temsil eder ve deposit metodu, ReentrantLock kullanılarak senkronize edilir. İki iş parçacığı oluşturulup başlatılır ve her biri 1000 kez para yatırma işlemi gerçekleştirir. joinmetodları ile ana iş parçacığı, diğer iş parçacıklarının tamamlanmasını bekler ve nihai bakiye yazdırılır.

Restoran Senaryosu

Bir restoranı yönettiğinizi düşünün. Mutfakta aşçılar (iş parçacıkları) yemek pişiriyor, garsonlar (iş parçacıkları) yemekleri müşterilere (kaynak) taşıyor. Aynı anda hem yemek pişirip hem de müşterilere hizmet veriyorsunuz. İşte bu, eşzamanlılık ve çoklu iş parçacığı kullanımıdır.

Sonuç

Concurrency ve multithreading, Java’da performans ve kullanıcı deneyimini artırmak için güçlü araçlardır. İyi tasarlanmış bir eşzamanlılık modeli, uygulamanızın verimliliğini büyük ölçüde artırabilir. Ancak, bu araçları kullanırken dikkatli olmalı ve senkronizasyon sorunlarına dikkat etmelisiniz.

Unutmayın, her şey gibi, concurrency ve multithreading de doğru ve dikkatli kullanıldığında büyük avantajlar sağlar. Gerçek hayatta nasıl aynı anda birden fazla iş yapıyorsak, Java’da da aynı şekilde çalışmamıza olanak tanır. Şimdi, bu bilgileri kullanarak daha verimli ve güçlü uygulamalar geliştirebilirsiniz!

Kaynaklar

  • Java Concurrency in Practice by Brian Goetz
  • Effective Java by Joshua Bloch

Mutlu kodlamalar! 🚀

--

--

BilgeAdam Teknoloji
BilgeAdam Teknoloji

Published in BilgeAdam Teknoloji

BilgeAdam Teknoloji yazılım geliştiricilerinin deneyimlediği makalelerinin bir çatı altında toplandığı tüm yazılım geliştiricilerin faydalanması için oluşturduğu paylaşım sayfasıdır.

Umut Akbulut
Umut Akbulut

Written by Umut Akbulut

"Tech leader & Software Architect. Passionate about digital transformation, microservices, and innovation in the finance and tech sectors."

No responses yet