multithreading etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
multithreading etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

Junit5'de birim testleri ve entegrasyon testleri nasıl paralel çalıştırılır?



JUnit 5'de birim testlerini ve entegrasyon testlerini paralel çalıştırmak için aşağıdaki adımları izleyebilirsiniz:

Maven veya Gradle Yapılandırması

JUnit 5'de paralel test çalıştırma özelliklerini kullanabilmek için Maven veya Gradle yapılandırmanızı güncellemeniz gerekebilir.

Maven

Maven kullanıyorsanız, maven-surefire-plugin ve maven-failsafe-plugin eklentilerini yapılandırmanız gerekiyor.

pom.xml:

xml
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M5</version> <configuration> <parallel>methods</parallel> <useUnlimitedThreads>true</useUnlimitedThreads> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.0.0-M5</version> <configuration> <parallel>methods</parallel> <useUnlimitedThreads>true</useUnlimitedThreads> </configuration> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> </plugins> </build> ... </project>

Gradle

Gradle kullanıyorsanız, test ve integrationTest görevlerini paralel çalışacak şekilde yapılandırabilirsiniz.

build.gradle:

groovy
plugins { id 'java' } repositories { mavenCentral() } dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } test { useJUnitPlatform() maxParallelForks = Runtime.runtime.availableProcessors() } task integrationTest(type: Test) { useJUnitPlatform() shouldRunAfter test maxParallelForks = Runtime.runtime.availableProcessors() testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath } sourceSets { integrationTest { compileClasspath += sourceSets.main.output + sourceSets.test.output runtimeClasspath += sourceSets.main.output + sourceSets.test.output } } configurations { integrationTestImplementation.extendsFrom testImplementation integrationTestRuntimeOnly.extendsFrom testRuntimeOnly }

JUnit 5 Konfigürasyonu

JUnit Platform Properties

JUnit 5'de paralel çalıştırma ayarlarını junit-platform.properties dosyasında yapabilirsiniz.

src/test/resources/junit-platform.properties:

properties
junit.jupiter.execution.parallel.enabled = true junit.jupiter.execution.parallel.mode.default = concurrent junit.jupiter.execution.parallel.config.strategy = dynamic

Bu ayarlar, JUnit 5 testlerini paralel olarak çalıştırmak için gerekli konfigürasyonları sağlar.

Testlerin Ayrılması

Birim testleri ve entegrasyon testlerini ayırmak için genellikle farklı paketler veya adlandırma kuralları kullanılır.

  • Birim testleri için src/test/java dizinini kullanabilirsiniz.
  • Entegrasyon testleri için src/integrationTest/java gibi ayrı bir dizin oluşturabilirsiniz.

Bu yapılandırmalarla birlikte JUnit 5 testlerini paralel olarak çalıştırabilir ve test süresini kısaltabilirsiniz.

Bana Java thread konusunu bir ilkokul mezununa anlatır gibi anlatır mısın? Kod örnekleri ile



Tabii, Java'daki "thread" (iş parçacığı) konusunu ilkokul mezunu birine anlatmak için basit ve anlaşılır bir dille açıklayacağım.


Java'da bir "thread", sanki bir bilgisayar programının içindeki küçük bir çalışan gibidir. Normalde, bir bilgisayar programı sırayla, birer birer işler yapar. Ama bazen, özellikle birden fazla işi aynı anda yapması gerektiğinde, bu "thread"ler devreye girer.


Bunu bir pizza dükkanına benzetebiliriz. Normalde, bir çalışan sipariş alır, pizzayı hazırlar ve pişirir. Ama dükkan çok meşgul olduğunda, bir çalışan sipariş alırken, başka bir çalışan pizzayı hazırlayabilir ve bir başkası da pişirebilir. Her bir çalışan, pizza dükkanının bir "thread"i gibidir ve hepsi aynı anda farklı işler yapabilir.


Java'da da bu "thread"ler, programın farklı bölümlerinde aynı anda çalışabilirler. Bu sayede, program daha hızlı ve verimli çalışır. Örneğin, bir "thread" dosya indirirken, başka bir "thread" ekranda animasyon gösterebilir.


Son olarak, tıpkı pizza dükkanındaki çalışanların birbiriyle iyi iletişim kurması gerektiği gibi, Java'daki "thread"lerin de birbiriyle doğru şekilde iletişim kurması önemlidir. Yoksa, karışıklıklar ve hatalar oluşabilir.


Bu, Java'daki "thread"lerin temel bir açıklamasıdır. İleride, daha fazla bilgi ve detay öğrendikçe, bu konu üzerinde daha da ustalaşabilirsin.


Java'daki thread'lerin nasıl çalıştığını daha iyi anlamak için, biraz daha detay ekleyelim:


Thread Oluşturmak

Java'da thread oluşturmanın iki yolu vardır:


Thread sınıfını genişleterek: Kendi sınıfınızı oluşturur ve Thread sınıfından türetirsiniz. Sonra run metodunu override ederek, thread'in yapacağı işi tanımlarsınız.

Runnable arayüzünü uygulayarak: Bir sınıf oluşturur ve Runnable arayüzünü uygularsınız. Sonra run metodunu uygulayarak, thread'in ne yapacağını tanımlarsınız. Bu sınıfın bir örneğini alıp yeni bir Thread nesnesine verirsiniz.

Thread Başlatmak

Thread oluşturduktan sonra, start metodunu çağırarak thread'i başlatırsınız. Bu, Java'nın thread'in run metodunu çalıştırmasını sağlar.


Thread'lerin Özellikleri

Eşzamanlılık (Concurrency): Birden fazla thread, işleri aynı anda yaparak programın daha hızlı çalışmasını sağlar.

Kaynak Paylaşımı: Thread'ler aynı bellek alanını ve kaynakları paylaşır, bu da veri paylaşımını kolaylaştırır.

Senkronizasyon: Birden fazla thread aynı kaynağa erişmeye çalıştığında, veri tutarsızlığını önlemek için senkronizasyon mekanizmaları kullanılır.

Thread'lerin Kullanım Alanları

Arka Plan İşlemleri: Dosya indirme, veritabanı işlemleri gibi arka planda çalışması gereken işlemler için kullanılır.

Kullanıcı Arayüzü: Kullanıcı arayüzünün donmadan çalışmasını sağlamak için arka planda işlemleri thread'ler üzerinde yürütülür.

Dikkat Edilmesi Gerekenler

Thread Güvenliği: Birden fazla thread'in aynı veriye eriştiği durumlarda, veri tutarlılığını korumak önemlidir.

Deadlock: İki veya daha fazla thread birbirini beklerse, programın kilitlenmesine (deadlock) yol açabilir. Bunu yönetmek önemlidir.

Bu temel bilgilerle, Java'da thread'lerin nasıl çalıştığını ve ne için kullanıldığını anlamaya başlayabilirsiniz. İlerledikçe, bu konuları daha detaylı inceleyerek uygulamalı örneklerle pekiştirebilirsiniz.


Elbette, Java thread'leri hakkında daha fazla detay vererek devam edelim:


Thread Öncelikleri

Java'da her thread'in bir önceliği vardır. Bu öncelik, işletim sistemi tarafından thread'lere ne kadar işlemci zamanı ayrılacağını belirler. Öncelikler 1 (en düşük) ile 10 (en yüksek) arasında değişir. Normal öncelik 5'tir. Bir thread'in önceliğini setPriority() metodu ile ayarlayabilirsiniz.


Thread Durumları

Java thread'leri çeşitli durumlarda olabilir:



New: Thread oluşturuldu ama henüz başlatılmadı.

Runnable: Thread çalışabilir durumda, işlemci bekliyor.

Blocked: Thread, bir kaynağa erişmeyi bekliyor.

Waiting: Thread diğer bir thread'in işlemi bitirmesini bekliyor.

Timed Waiting: Thread belirli bir süre boyunca veya bir olayın gerçekleşmesini bekliyor.

Terminated: Thread'in çalışması sona erdi.

Thread Yönetimi

sleep(): Thread'i belirli bir süre için duraklatır.

join(): Bir thread'in başka bir thread'in tamamlanmasını beklemesini sağlar.

interrupt(): Uykuda olan bir thread'i uyandırır veya çalışan bir thread'e kesinti isteği gönderir.

Senkronizasyon

Java'da birden fazla thread'in aynı kaynağa erişmesini düzenlemek için senkronizasyon kullanılır. synchronized anahtar kelimesi, aynı anda sadece bir thread'in belirli bir kaynağa erişmesini sağlar. Böylece veri tutarlılığı korunur.


Thread Havuzları

Büyük uygulamalarda, çok sayıda thread oluşturmak ve yönetmek zor olabilir. Bu durumda, thread havuzları kullanılır. Java'da ExecutorService ve diğer sınıflar, thread'leri etkili bir şekilde yönetmek ve kaynak kullanımını optimize etmek için thread havuzları oluşturmanıza olanak tanır.


Thread Güvenliği

Bir sınıf veya metot thread güvenli olduğunda, birden fazla thread tarafından eş zamanlı olarak kullanılabilir ve beklenmeyen davranışlara neden olmaz. Thread güvenliği, veri tutarlılığını korumak için kritik öneme sahiptir.


Ölümcül Hatalar (Deadlock)

Thread'ler birbirlerinin kaynaklarını beklediğinde ve hiçbiri ilerleyemediğinde deadlock meydana gelir. Deadlockları tespit etmek ve önlemek, çok-threadli programlamada önemli bir beceridir.


Java'daki thread'ler, programlamada paralellik ve eşzamanlılığı yönetmek için güçlü araçlardır. İyi bir anlayış ve uygulama, etkili ve verimli yazılımlar oluşturmanıza yardımcı olur. Bu konseptler üzerine pratik yaparak ve gerçek dünya senaryolarında uygulayarak bilginizi derinleştirebilirsiniz.


Java'daki thread konseptini daha da detaylandırmak için, ileri düzey konseptlere ve özelliklere de değinelim:


Volatile Anahtar Kelimesi

Java'da volatile anahtar kelimesi, bir değişkenin değerinin farklı thread'ler tarafından her zaman doğru bir şekilde okunmasını ve yazılmasını sağlar. Bu, değişkenin değerinin her zaman ana bellekten okunacağını ve oraya yazılacağını garanti eder. Bu, değişkenlerin thread'ler arası güvenli bir şekilde paylaşılmasını sağlar.


ThreadLocal Sınıfı

ThreadLocal sınıflar, thread özgü veri saklamak için kullanılır. Her thread, ThreadLocal değişken için kendi kopyasını korur. Bu, thread'lerin veri paylaşımında karşılaştıkları sorunları azaltır ve veri izolasyonunu sağlar.


Lock İnterface ve Reentrant Lock

Java'da Lock interface'i, daha gelişmiş senkronizasyon mekanizmaları sağlar. ReentrantLock sınıfı, geleneksel synchronized bloklarına göre daha fazla esneklik ve kontrol sunar. Örneğin, bir ReentrantLock ile bir thread, başka bir thread tarafından alınmış bir kilidi beklerken zaman aşımına uğrayabilir.


Condition İnterface

Condition interface'i, bir Lock ile birlikte kullanılarak, thread'ler arasında daha ince taneli kontrol ve koordinasyon sağlar. Örneğin, belirli bir koşulun gerçekleşmesini bekleyen thread'leri uyandırmak veya uyutmak için kullanılabilir.


Semaphore Sınıfı

Semaphore sınıfı, belirli bir kaynağın eş zamanlı olarak erişilebilecek sınırlı sayıda iznini yönetmek için kullanılır. Bu, özellikle sınırlı kaynaklara erişimde kullanışlıdır.


CountDownLatch Sınıfı

CountDownLatch bir veya daha fazla thread'in, diğer thread'lerin belirli işlemleri tamamlamasını beklemesini sağlar. Bu, thread'ler arası senkronizasyon için kullanışlı bir araçtır.


CyclicBarrier Sınıfı

CyclicBarrier, belirli bir sayıda thread'in bir noktada buluşup birlikte devam etmesini sağlar. Bu, parçalara ayrılmış görevlerin bir araya getirilmesinde kullanılır.


CompletableFuture

CompletableFuture, asenkron programlama için kullanılır. Bu sınıf, gelecekteki bir sonucu temsil eder ve bu sonucun thread'ler arası bağımsız bir şekilde işlenmesini sağlar.


Thread'lerin Güvenliği ve Performansı

Java'da thread programlaması, doğru yapılmadığında karmaşık hatalara yol açabilir. Bunun için, thread güvenliği, deadlocks, race conditions ve memory consistency errors gibi konulara dikkat edilmelidir. Ayrıca, gereksiz thread kullanımı sistem kaynaklarını boş yere tüketebilir, bu nedenle thread'lerin akıllıca kullanılması önemlidir.


Java'daki thread konseptleri, yazılım geliştirme dünyasında paralel ve asenkron işlemlerin yönetilmesi için güçlü araçlar sunar. Bu konuları anlamak ve doğru şekilde uygulamak, yazılım geliştiriciler için çok önemlidir. İyi bir anlayış ve doğru uygulama, yazılımınızın performansını ve güvenilirliğini önemli ölçüde artırabilir.


Java'da thread kullanımına dair bazı temel kod örnekleri vereceğim. Her bir örnek, yukarıda bahsettiğim konseptlerden birine odaklanacak.


1. Thread Sınıfını Genişleterek Thread Oluşturma

java

Copy code

class MyThread extends Thread {

    public void run() {

        System.out.println("Thread çalışıyor.");

    }

}


public class Main {

    public static void main(String args[]) {

        MyThread t1 = new MyThread();

        t1.start();

    }

}

2. Runnable Arayüzünü Kullanarak Thread Oluşturma

java

Copy code

class MyRunnable implements Runnable {

    public void run() {

        System.out.println("Runnable kullanılarak thread çalışıyor.");

    }

}


public class Main {

    public static void main(String args[]) {

        MyRunnable myRunnable = new MyRunnable();

        Thread t2 = new Thread(myRunnable);

        t2.start();

    }

}

3. Thread Öncelikleri

java

Copy code

public class Main {

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {

            System.out.println("Thread 1 önceliği: " + Thread.currentThread().getPriority());

        });

        Thread t2 = new Thread(() -> {

            System.out.println("Thread 2 önceliği: " + Thread.currentThread().getPriority());

        });


        t1.setPriority(Thread.MIN_PRIORITY); // 1

        t2.setPriority(Thread.MAX_PRIORITY); // 10


        t1.start();

        t2.start();

    }

}

4. Thread Synchronization (Senkronizasyon)

java

Copy code

class Counter {

    private int count = 0;


    public synchronized void increment() {

        count++;

    }


    public int getCount() {

        return count;

    }

}


public class Main {

    public static void main(String[] args) throws InterruptedException {

        Counter counter = new Counter();


        Thread t1 = new Thread(() -> {

            for (int i = 0; i < 10000; i++) {

                counter.increment();

            }

        });


        Thread t2 = new Thread(() -> {

            for (int i = 0; i < 10000; i++) {

                counter.increment();

            }

        });


        t1.start();

        t2.start();


        t1.join();

        t2.join();


        System.out.println("Toplam: " + counter.getCount());

    }

}

Bu örnekler, Java'da thread'lerin nasıl oluşturulacağına ve basit senkronizasyon tekniklerine bir giriş niteliğindedir. Daha ileri konseptler ve daha karmaşık senaryolar için, Java'nın multithreading ve concurrency API'leri ile daha fazla deneyim kazanmak ve resmi dokümantasyonu incelemek faydalı olacaktır.


Elbette, Java'da thread'lerle ilgili daha ileri düzey konseptler için ilave kod örnekleri sunacağım.


5. volatile Anahtar Kelimesi Kullanımı

volatile değişkenler, değerlerinin thread'ler arasında tutarlı kalmasını sağlar.


java

Copy code

public class VolatileExample {

    private static volatile boolean flag = true;


    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(() -> {

            while (flag) {

                // İşlemler

            }

            System.out.println("Thread durdu.");

        });


        t1.start();


        Thread.sleep(1000); // 1 saniye sonra flag'i false yap

        flag = false;

        System.out.println("Flag değiştirildi ve thread durdurulacak.");

    }

}

6. ReentrantLock Kullanımı

ReentrantLock, daha ince taneli kilitleme mekanizmaları sağlar.


java

Copy code

import java.util.concurrent.locks.ReentrantLock;


public class LockExample {

    private final ReentrantLock lock = new ReentrantLock();

    private int count = 0;


    public void increment() {

        lock.lock();

        try {

            count++;

        } finally {

            lock.unlock();

        }

    }


    public static void main(String[] args) throws InterruptedException {

        LockExample example = new LockExample();


        Thread t1 = new Thread(example::increment);

        Thread t2 = new Thread(example::increment);


        t1.start();

        t2.start();


        t1.join();

        t2.join();


        System.out.println("Toplam: " + example.count);

    }

}

7. CountDownLatch Kullanımı

CountDownLatch, bir thread'in diğer thread'lerin işlemlerini tamamlamasını beklemesi için kullanılır.


java

Copy code

import java.util.concurrent.CountDownLatch;


public class CountDownLatchExample {

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch latch = new CountDownLatch(3);


        for (int i = 1; i <= 3; i++) {

            new Thread(() -> {

                System.out.println("Thread işlemi tamamladı.");

                latch.countDown();

            }).start();

        }


        latch.await(); // Üç thread'in tamamlanmasını bekle

        System.out.println("Tüm thread'ler tamamlandı.");

    }

}

8. Semaphore Kullanımı

Semaphore, kaynaklara sınırlı erişim sağlamak için kullanılır.


java

Copy code

import java.util.concurrent.Semaphore;


public class SemaphoreExample {

    private static final Semaphore semaphore = new Semaphore(2);


    public static void main(String[] args) {

        Runnable task = () -> {

            try {

                semaphore.acquire();

                System.out.println("Thread " + Thread.currentThread().getId() + " çalışıyor.");

                Thread.sleep(2000); // İşlem süresi simülasyonu

            } catch (InterruptedException e) {

                e.printStackTrace();

            } finally {

                semaphore.release();

                System.out.println("Thread " + Thread.currentThread().getId() + " bitti.");

            }

        };


        for (int i = 0; i < 5; i++) {

            new Thread(task).start();

        }

    }

}

Bu örnekler, Java'daki ileri düzey thread yönetimi ve senkronizasyon mekanizmalarını göstermektedir. İleri düzey multithreading ve concurrency konularını kavramak, pratik yapmak ve Java'nın bu konudaki resmi dokümantasyonunu incelemek önemlidir. Bu sayede daha karmaşık ve performanslı uygulamalar geliştirebilirsiniz.

Java'da ExecutorService ile insanmış gibi bir röportaj yapmış olsaydım, röportaj nasıl olurdu?





Java'da ExecutorService kullanarak bir röportaj yapma fikri oldukça ilginç. Böyle bir röportaj, ExecutorService'in çoklu görev yürütme yeteneklerini kullanarak, bir dizi soruyu paralel olarak işleyebilir. İşte böyle bir senaryoda olası bir röportaj örneği:


Röportajcı: Merhaba, ExecutorService'i kullanarak bu röportajı yapacağız. İlk sorum, Java'daki ExecutorService nedir?


ExecutorService: Merhaba! ExecutorService, Java'da eş zamanlı görev yürütme için bir çerçeve sağlar. Görevleri (Runnable veya Callable olarak) yürütebilen ve yönetebilen bir thread havuzu sağlar.


Röportajcı: Peki, ExecutorService'in avantajları nelerdir?


ExecutorService: ExecutorService, görev yönetimini kolaylaştırır, kaynak kullanımını optimize eder ve çoklu görev işleme kapasitesini artırır. Ayrıca, kodun daha okunabilir ve bakımının daha kolay olmasını sağlar.


Röportajcı: Java'da ExecutorService nasıl kullanılır?


ExecutorService: ExecutorService kullanımı genellikle Executors fabrika sınıfı aracılığıyla bir executor oluşturmakla başlar. Sonra, submit() metodunu kullanarak görevleri (Runnable veya Callable) yürütebilirsiniz. İşlemler tamamlandığında, shutdown() metodunu kullanarak kaynakları serbest bırakırsınız.


Röportajcı: Son olarak, ExecutorService kullanırken yaygın yapılan hatalar nelerdir?


ExecutorService: En yaygın hatalardan biri, kaynakları düzgün bir şekilde serbest bırakmamaktır. shutdown() veya shutdownNow() metodlarını çağırmayı unutmak, bellek sızıntılarına ve performans sorunlarına yol açabilir. Ayrıca, çok fazla thread oluşturmak da sistem kaynaklarını gereksiz yere tüketebilir.


Röportajcı: Çok iyi. Şimdi, ExecutorService ile ilgili biraz daha derine inelim. Örneğin, Callable ve Runnable arasındaki fark nedir?


ExecutorService: Runnable ve Callable her ikisi de yürütülebilir görevleri temsil eder, ancak ana fark, Callable'ın bir sonuç döndürebilmesi ve istisna fırlatabilmesidir. Runnable'ın run() metodu bir değer döndürmez ve istisnaları işlemez.


Röportajcı: Peki ya Future nesnesi? Bu terim ExecutorService bağlamında nasıl kullanılır?


ExecutorService: Future nesnesi, asenkron bir görevin sonucunu temsil eder. ExecutorService'in submit() metodu, bir Future döndürür. Bu Future, görevin tamamlanıp tamamlanmadığını kontrol etmek, görevin sonucunu almak ve gerekirse görevi iptal etmek için kullanılabilir.


Röportajcı: Anladım. Son olarak, ExecutorService'in ölçeklenebilirliği ve performansı hakkında ne söyleyebilirsiniz?


ExecutorService: ExecutorService, özellikle thread havuzları ile çok ölçeklenebilirdir. Executors sınıfı, farklı türlerde executor havuzları oluşturmanıza olanak tanır. Örneğin, newFixedThreadPool sabit sayıda thread içerirken, newCachedThreadPool gerektiğinde thread oluşturur ve ihtiyaç duyulmadığında onları kapatır. Bu, uygulamanızın ihtiyaçlarına bağlı olarak kaynak kullanımını optimize etmenize yardımcı olur.



Kod örnekleri ile röportaja devam et


Elbette, kod örnekleriyle röportaja devam edelim:


Röportajcı: Harika! Şimdi, bir ExecutorService oluşturmak için basit bir Java kodu örneği gösterebilir misiniz?


ExecutorService:


java

Copy code

ExecutorService executor = Executors.newFixedThreadPool(4); // 4 thread'lik bir havuz oluşturuluyor.

Röportajcı: Peki, bu executor'a bir Runnable görevi nasıl ekleyebiliriz?


ExecutorService:


java

Copy code

executor.submit(() -> {

    System.out.println("Runnable görev çalıştırılıyor.");

});

Röportajcı: Callable görevlerle nasıl çalışılır?


ExecutorService:


java

Copy code

Future<String> future = executor.submit(() -> {

    return "Callable'dan dönen sonuç.";

});


try {

    String sonuc = future.get(); // Görevin tamamlanmasını bekler ve sonucu alır.

    System.out.println("Callable sonucu: " + sonuc);

} catch (InterruptedException | ExecutionException e) {

    e.printStackTrace();

}

Röportajcı: Executor'u nasıl düzgün bir şekilde kapatırsınız?


ExecutorService:


java

Copy code

executor.shutdown(); // Görevlerin tamamlanmasını bekler.

try {

    if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {

        executor.shutdownNow();

    }

} catch (InterruptedException e) {

    executor.shutdownNow();

}

Röportajcı: Son olarak, ExecutorService kullanırken dikkat edilmesi gereken birkaç iyi uygulama kuralı var mı?


ExecutorService: Evet, öncelikle kaynak yönetimine dikkat edin. Executor'u kullanmayı bitirdiğinizde mutlaka kapatın. Ayrıca, iş yükünüze uygun thread havuzu boyutunu seçmeye özen gösterin. Çok fazla thread, bellek ve CPU üzerinde gereksiz yük oluşturabilir. Ve son olarak, Callable ve Future kullanarak görevlerinizi doğru şekilde yönetin, böylece asenkron görevlerden en iyi şekilde yararlanabilirsiniz.


Röportajcı: Bu bilgiler ve örnekler için teşekkürler! Java'nın eş zamanlılık araçları hakkında çok daha iyi bir fikir edindim.


Bu kod örnekleri ve açıklamalar, ExecutorService'in temel kullanımını gösteriyor ve Java'da eş zamanlı programlamayı anlamak için iyi bir başlangıç noktası oluşturuyor.




Thread Pool Nedir?

Thread pool, sınırlı sayıda ve önceden oluşturulmuş iş parçacıklarını içeren bir havuzdur. Bu havuz, görevleri sırayla işlemek için bu iş parçacıklarını yeniden kullanır. Thread pool kullanmanın temel amacı, her görev için yeni bir iş parçacığı oluşturmanın getirdiği maliyeti ve karmaşıklığı azaltmaktır.


Avantajları

Performans Artışı: İş parçacığı oluşturmanın ve yok etmenin maliyeti yüksektir. Thread pool, bu maliyeti azaltarak uygulamanın genel performansını artırır.

Kaynak Kullanımının Optimizasyonu: Sınırlı sayıda iş parçacığı kullanarak, sistem kaynaklarının aşırı tüketilmesini önler.

Daha İyi Görev Yönetimi: Görevler, havuzdaki iş parçacıkları arasında etkili bir şekilde dağıtılır, böylece görev yükü dengelenir.

Yüksek Tepki Süresi: Yeni bir görev geldiğinde, havuzda zaten mevcut olan bir iş parçacığı hemen bu görevi üstlenebilir.

Java'da Thread Pool Kullanımı

Java'da thread pool oluşturmak ve kullanmak için java.util.concurrent paketindeki Executor çerçevesi kullanılır. ExecutorService arayüzü, iş parçacığı havuzunu yönetmek için çeşitli metotlar sağlar. En yaygın kullanılan thread pool sınıfları şunlardır:


Executors.newFixedThreadPool(int): Sabit sayıda iş parçacığı içeren bir havuz oluşturur.

Executors.newCachedThreadPool(): Gerektiğinde yeni iş parçacıkları oluşturabilen ve kullanılmayan iş parçacıklarını otomatik olarak yok edebilen esnek bir havuz oluşturur.

Executors.newSingleThreadExecutor(): Yalnızca tek bir iş parçacığı içeren bir havuz oluşturur.

Örnek Kullanım

java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class ThreadPoolExample {

    public static void main(String[] args) {

        // 5 iş parçacığına sahip bir thread pool oluştur

        ExecutorService executor = Executors.newFixedThreadPool(5);


        // Görevleri havuza ekle

        for (int i = 0; i < 10; i++) {

            Runnable worker = new WorkerThread("" + i);

            executor.execute(worker);

        }


        // İş parçacıklarını kapat

        executor.shutdown();

        while (!executor.isTerminated()) {

            // Tüm görevlerin tamamlanmasını bekle

        }


        System.out.println("Tüm görevler tamamlandı");

    }

}


class WorkerThread implements Runnable {

    private String command;


    public WorkerThread(String s){

        this.command = s;

    }


    @Override

    public void run() {

        System.out.println(Thread.currentThread().getName()+" Başlatıldı. Komut = " + command);

        processCommand();

        System.out.println(Thread.currentThread().getName()+" Bitirildi.");

    }


    private void processCommand() {

        try {

            Thread.sleep(5000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }


    @Override

    public String toString(){

        return this.command;

    }

}

Bu kod örneğinde, 5 iş parçacığı içeren bir thread pool oluşturulur ve bu havuz 10 görevi sırayla işler. Her görev, WorkerThread sınıfının bir örneği olarak tanımlanır ve execute() metodu ile havuza eklenir.


Java'nın ExecutorService arayüzünde submit ve execute metotları iş parçacığı havuzuna görev eklemek için kullanılır, ancak aralarında önemli farklar vardır:


execute Metodu

execute metodu, Runnable nesneleri kabul eder ve geriye bir şey dönmez (void).

execute, gönderilen görevin tamamlanmasını takip etmek için herhangi bir mekanizma sunmaz.

Genellikle görevin tamamlanmasını takip etmek veya sonucunu almak gerekmediğinde kullanılır.

submit Metodu

submit metodu, hem Runnable hem de Callable nesnelerini kabul eder.

submit metodu, Future tipinde bir nesne döndürür. Bu Future nesnesi, görevin tamamlanma durumunu takip etmeye ve görevin sonucunu almak için kullanılabilir. Callable görevleri için, bu sonuç görevin dönüş değeridir.

Genellikle görevin tamamlanma durumunu izlemek veya görevin sonucunu almak istediğiniz durumlarda kullanılır.

Java Thread State'leri




Java'da bir iş parçacığı, belirli bir durumda olabilir ve bu durumlar iş parçacığının ne durumda olduğunu belirtir. İşte bu durumlar:


NEW (Yeni): İş parçacığı oluşturulmuştur ancak henüz başlamamıştır.

RUNNABLE (Çalışabilir): İş parçacığı JVM (Java Sanal Makinesi) içinde yürütülmektedir.

BLOCKED (Engellendi): İş parçacığı engellenmiştir ve bir monitör beklemektedir.

WAITING (Beklemede): İş parçacığı, başka bir iş parçacığı tarafından uyanmayı beklemektedir.

TIMED_WAITING (Zamanlı Bekleme): İş parçacığı, belirli bir bekleme süresiyle başka bir iş parçacığı tarafından uyanmayı beklemektedir.

TERMINATED (Sonlandırıldı): İş parçacığı yürütmesini tamamlamıştır.

Bu durumlar, iş parçacığının yaşam döngüsünün farklı aşamalarını temsil eder ve iş parçacığının ne yaptığını veya neyle meşgul olduğunu anlamanıza yardımcı olur.

Eşzamanlılık (Concurrency),Multithreading (Çoklu İş Parçacığı),Paralellik (Parallelism) arasındaki farklar

Multithreading, paralellik ve eşzamanlılık (concurrency), karmaşık hesaplama işlemlerinin hızlandırılmasına yardımcı olan üç farklı kavramdır. Bu terimler arasındaki farklar aşağıda açıklanmıştır:



Eşzamanlılık (Concurrency):



Eşzamanlılık, birden fazla işlemin yalnızca bir işlemcinin bulunduğu sistemlerde bile eş zamanlı olarak yürütülmesini sağlar.

Bu, her işlemin bir sonrakine hızlı bir şekilde geçiş yaparak tek bir işlemcinin birden fazla işlemi eş zamanlı olarak yürütmesine olanak tanır. Böylece her bir işlem diğer işlemlerle neredeyse eş zamanlı olarak ilerler.

İlgili işlemler aynı anda çalışmıyormuş gibi görünebilir, ancak işletim sistemi onları o kadar hızlı değiştirir ki, kullanıcı için aynı anda çalışıyormuş gibi görünürler.

Multithreading (Çoklu İş Parçacığı):






Multithreading, aynı uygulama içindeki birden fazla iş parçacığının (thread) eş zamanlı olarak çalışmasına izin verir.

Bu, tek bir işlem içinde farklı işlemlerin paralel olarak yürütülmesine imkan tanır.

İş parçacıkları, aynı hafıza alanını paylaştığından, veri paylaşımı ve iletişim diğer paralel yürütme türlerine göre daha kolay olabilir.

Multithreading, eşzamanlılıkla yakından ilişkilidir, çünkü iş parçacıkları eş zamanlı olarak yürütülür.

Paralellik (Parallelism):



Paralellik, aynı anda birden fazla işlemin yürütülmesi anlamına gelir.

Bu, genellikle birden fazla işlemci veya işlemci çekirdeği kullanılarak gerçekleştirilir, böylece her işlemci veya çekirdek aynı anda farklı bir işlem üzerinde çalışabilir.

Paralellik, özellikle büyük ve karmaşık hesaplama problemlerini daha hızlı bir şekilde çözmek için kullanılır.

Özetle, eşzamanlılık daha çok işlemlerin birbirine hızlı bir şekilde geçiş yapmasını sağlarken, çoklu iş parçacığı yürütme aynı uygulama içinde paralel işlemleri yürütme üzerine odaklanır ve paralellik, tam anlamıyla aynı anda birden fazla işlemin yürütülmesiyle ilgilidir.


Multithreading'de Paralellik (Parallelism) mümkün müdür?


Evet, multithreading ile paralellik (parallelism) mümkündür. Bu iki kavram, farklı bağlamlarda kullanıldığında, birbirleriyle ilişkili olabilirler.


Multithreading, bir işlemin birden fazla iş parçacığına (thread) bölündüğü bir yürütme modelidir. Bu iş parçacıkları, eşzamanlı olarak yürütülebilir, yani bir iş parçacığı beklerken diğer iş parçacıkları çalışabilir.


Paralellik, ise birden fazla işlemcinin veya işlemci çekirdeğinin aynı anda farklı görevleri yürütmesi anlamına gelir. Bu, aynı programın farklı parçalarının veya farklı programların aynı anda çalıştığı anlamına gelir.


Multithreading'in paralellikle birleştirilmesi, birden fazla işlemcinin veya çekirdeğin aynı anda farklı iş parçacıklarını yürütmesine olanak tanır. Bu, özellikle çok çekirdekli işlemcilerde etkilidir, çünkü her iş parçacığı, işlemcinin farklı bir çekirdeğinde yürütülebilir.

Bu tür bir yürütme, işlemlerin daha hızlı tamamlanmasına yardımcı olabilir, çünkü iş parçacıkları birbirlerini beklemek yerine aynı anda çalışabilirler. Bununla birlikte, çoklu iş parçacığı yürütme karmaşık olabilir ve uygun senkronizasyon ve veri paylaşımı gerektirebilir, aksi takdirde veri yarışı gibi problemler ortaya çıkabilir.


Özetle, multithreading ile paralellik mümkündür ve birlikte kullanıldığında, işlemlerin daha hızlı ve etkin bir şekilde yürütülmesine yardımcı olabilir.

Java Threads kod örnekleri ile ExecuterService nedir? Neden kullanılır? Avantajları nelerdir? Dezavantajları nelerdir? Mülakat soruları ve cevapları


ExecutorService, Java'nın java.util.concurrent paketinde yer alan bir arayüzdür. İş parçacığı (thread) havuzunu yönetmek ve iş parçacığı tabanlı çoklu görev yürütmek için kullanılır. ExecutorService, yüksek düzeyde bir arayüz sağlar ve gelişmiş bir iş parçacığı yönetimi sağlar.




ExecutorService kullanmanın bazı nedenleri şunlardır:


İş parçacığı oluşturma ve yönetme işlemlerini gizler: ExecutorService, iş parçacığı oluşturma ve yönetmeyle ilgili tüm karmaşıklığı gizler. Bu sayede geliştiriciler, iş parçacığı oluşturma, başlatma ve sonlandırma gibi düşük seviyeli detaylarla uğraşmak zorunda kalmadan daha yüksek seviyeli bir arayüz üzerinden işlerini gerçekleştirebilirler.


İş parçacığı havuzunu kullanarak performansı artırır: ExecutorService, bir iş parçacığı havuzu kullanarak işleri dağıtabilir ve aynı anda birden çok işi eşzamanlı olarak çalıştırabilir. Bu, sistem kaynaklarını daha etkin bir şekilde kullanmanızı ve performansı artırmanızı sağlar.


İşler arasındaki iletişimi ve senkronizasyonu yönetir: ExecutorService, iş parçacıkları arasındaki iletişimi ve senkronizasyonu yönetmek için çeşitli mekanizmalar sağlar. Örneğin, Future nesnelerini kullanarak işin sonucunu elde edebilir veya başka bir iş parçacığı üzerinde beklemek için CountDownLatch veya CyclicBarrier gibi senkronizasyon araçlarını kullanabilirsiniz.


ExecutorService'in bazı avantajları şunlardır:


Daha iyi performans: İş parçacığı havuzunu kullanarak çoklu görevleri eşzamanlı olarak yürütebilir ve böylece performansı artırabilirsiniz. İş parçacıklarını tekrar tekrar oluşturmak yerine, havuzdaki mevcut iş parçacıklarını kullanabilirsiniz.


Kaynak yönetimi: ExecutorService, iş parçacıklarının oluşturulmasını ve sonlandırılmasını otomatik olarak yönetir. Bu sayede, kaynakların etkin bir şekilde kullanılmasını sağlar ve olası hataları en aza indirir.


İş parçacıkları arasındaki iletişimi kolaylaştırır: ExecutorService, iş parçacıkları arasında iletişim ve senkronizasyon için hazır araçlar sağlar. Bu sayede, iş parçacıkları arasında veri paylaşımı veya senkronizasyonu kolayca gerçekleştirebilirsiniz.


Bununla birlikte, ExecutorService'in bazı dezavantajları da vardır:


Kaynak tükenmesi: Eğer iş parçacığı havuzunda çok fazla iş parçacığı oluşturursanız, sistem kaynaklarının tükenmesine neden olabilirsiniz. Bu durumda, performans yerine sistem performansı düşebilir.


İş parçacığı oluşturma maliyeti: Her iş parçacığı oluşturma işlemi bir maliyete sahiptir. Eğer çok küçük işler için sürekli olarak yeni iş parçacıkları oluşturursanız, bu iş parçacığı oluşturma maliyeti zamanla artabilir.


Java'da ExecutorService kullanarak bir iş parçacığı havuzu oluşturmanın örnek kodu aşağıdaki gibidir:


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(5);


        // İşleri havuza gönderme

        for (int i = 0; i < 10; i++) {

            Runnable worker = new WorkerThread("Task " + i);

            executor.execute(worker);

        }


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

        while (!executor.isTerminated()) {

            // Havuzun tamamen sonlandırılmasını bekleyin

        }


        System.out.println("İşler tamamlandı.");

    }

}


class WorkerThread implements Runnable {

    private String taskName;


    public WorkerThread(String taskName) {

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, ExecutorService'in bir örneği olan executor oluşturuluyor. Ardından, execute() yöntemi kullanılarak işler havuza gönderiliyor. WorkerThread sınıfı, her bir işi temsil eden iş parçacığı görevini gerçekleştiriyor. İşler tamamlandıktan sonra shutdown() yöntemi ile havuz kapatılıyor ve isTerminated() yöntemi ile tamamen sonlandırılması bekleniyor.


Bu şekilde, ExecutorService kullanarak iş parçacığı havuzunu yönetebilir ve işleri daha verimli bir şekilde yürütebilirsiniz.


Senaryo 1: Birden çok işi eşzamanlı olarak yürütmek


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(3);


        // İşleri havuza gönderme

        executor.execute(new WorkerThread("Task 1"));

        executor.execute(new WorkerThread("Task 2"));

        executor.execute(new WorkerThread("Task 3"));


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class WorkerThread implements Runnable {

    private String taskName;


    public WorkerThread(String taskName) {

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, newFixedThreadPool(3) yöntemiyle iş parçacığı havuzu oluşturuluyor ve 3 iş gönderiliyor. Havuz, maksimum 3 iş parçacığına sahip olacak ve bu işler eşzamanlı olarak yürütülecektir.


Senaryo 2: İşlerin sonuçlarını elde etmek




java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // İşleri havuza gönderme ve Future nesnelerini alıma

        Future<Integer> result1 = executor.submit(new CalculationTask(5));

        Future<Integer> result2 = executor.submit(new CalculationTask(10));


        // Sonuçları elde etme

        try {

            int sum = result1.get() + result2.get();

            System.out.println("Toplam: " + sum);

        } catch (Exception e) {

            e.printStackTrace();

        }


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class CalculationTask implements Callable<Integer> {

    private int number;


    public CalculationTask(int number) {

        this.number = number;

    }


    public Integer call() throws Exception {

        // İş parçacığı tarafından gerçekleştirilecek hesaplama görevini burada tanımlayın

        int sum = 0;

        for (int i = 1; i <= number; i++) {

            sum += i;

        }

        return sum;

    }

}

Bu örnekte, submit() yöntemiyle işler havuza gönderilir ve her bir işin sonucunu temsil eden Future nesneleri elde edilir. Daha sonra get() yöntemi kullanılarak Future nesnelerinden sonuçlar alınır. Sonuçlar elde edildikten sonra iş parçacığı havuzu kapatılır.


ExecutorService, Java'da çoklu iş parçacığı yürütmek için güçlü bir araçtır. İş parçacığı havuzunu yönetmek, performansı artırmak ve iş parçacıkları arasında iletişimi kolaylaştırmak için kullanılabilir. Ancak, iş parçacığı sayısının dikkatlice yönetilmemesi ve iş parçacığı oluşturma maliyetinin göz ardı edilmesi gibi durumlarda dezavantajlara yol açabilir. Bu nedenle, ExecutorService'i kullanırken, uygulamanızın gereksinimlerine uygun olarak iş parçacığı sayısını ve kaynak kullanımını dikkatlice ayarlamalısınız.

Senaryo 3: İş Parçacığı Havuzu İçinde Belirli Aralıklarla Tekrarlanan Görevler


java

Copy code

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);


        // Görevi belirli aralıklarla tekrar etmesi için planlama

        executor.scheduleAtFixedRate(new Task(), 0, 1, TimeUnit.SECONDS);


        // Belirli bir süre sonra iş parçacığı havuzunu kapatma

        try {

            Thread.sleep(5000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        System.out.println("Görev çalışıyor...");

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, newScheduledThreadPool(1) yöntemiyle iş parçacığı havuzu oluşturulur ve belirli aralıklarla tekrar eden bir görev planlanır. scheduleAtFixedRate() yöntemi kullanılarak görev belirli bir süre sonra başlatılır ve belirtilen aralıklarla tekrarlanır. Daha sonra Thread.sleep() yöntemiyle havuzun belirli bir süre çalışmasını bekleriz ve ardından havuzu kapatırız.


Senaryo 4: İş Parçacığı Havuzunda Senkronizasyon Araçları Kullanma


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // Senkronizasyon aracı olarak CountDownLatch kullanma

        final CountDownLatch latch = new CountDownLatch(3);


        // İşleri havuza gönderme

        executor.execute(new WorkerThread(latch, "Task 1"));

        executor.execute(new WorkerThread(latch, "Task 2"));

        executor.execute(new WorkerThread(latch, "Task 3"));


        // Tüm işlerin tamamlanmasını bekleyin

        try {

            latch.await();

        } catch (InterruptedException e) {

            e.printStackTrace();

        }


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class WorkerThread implements Runnable {

    private CountDownLatch latch;

    private String taskName;


    public WorkerThread(CountDownLatch latch, String taskName) {

        this.latch = latch;

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

        try {

            TimeUnit.SECONDS.sleep(2);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        latch.countDown();

    }

}

Bu örnekte, CountDownLatch senkronizasyon aracını kullanarak iş parçacığı havuzunda görevlerin senkronize bir şekilde tamamlanmasını sağlıyoruz. Her iş parçacığı, görevi tamamladığında latch.countDown() yöntemini çağırarak bir sayaç değerini azaltır. Ana programda ise latch.await() yöntemi kullanılarak tüm işlerin tamamlanmasını bekleriz.


ExecutorService, iş parçacığı yönetimi için güçlü ve esnek bir araçtır. Farklı senaryolara uygun olarak iş parçacığı havuzunu oluşturabilir ve işleri yönetebilirsiniz. Bu sayede, çoklu görev yürütmeyi daha verimli hale getirebilir, iş parçacığı oluşturma ve yönetme işlemlerini kolaylaştırabilirsiniz. Ancak, iş parçacığı sayısı ve kaynak kullanımı gibi faktörleri dikkatlice ayarlamak önemlidir. Ayrıca, senkronizasyon ve iletişim gerektiren durumlarda uygun senkronizasyon araçlarını kullanmak önemlidir.


Senaryo 5: İş Parçacığı Havuzunda Gelecekte Gerçekleşecek Görevleri Planlama


java

Copy code

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);


        // Gelecekte gerçekleşecek bir görevi planlama

        executor.schedule(new Task(), 5, TimeUnit.SECONDS);


        // Belirli bir süre sonra iş parçacığı havuzunu kapatma

        try {

            Thread.sleep(10000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        System.out.println("Gelecekte gerçekleşecek görev çalıştı.");

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, schedule() yöntemi kullanılarak gelecekte gerçekleşecek bir görev planlanır. Görev, belirli bir süre sonra (5 saniye) iş parçacığı havuzunda çalıştırılacaktır. Daha sonra Thread.sleep() yöntemiyle havuzun belirli bir süre çalışmasını bekleriz ve ardından havuzu kapatırız.


Senaryo 6: İş Parçacığı Havuzunda İş Parçacıkları Arasında Veri Paylaşımı


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // Paylaşılan veriyi kullanarak işleri havuza gönderme

        SharedData sharedData = new SharedData();

        executor.execute(new WorkerThread(sharedData, "Task 1"));

        executor.execute(new WorkerThread(sharedData, "Task 2"));


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class WorkerThread implements Runnable {

    private SharedData sharedData;

    private String taskName;


    public WorkerThread(SharedData sharedData, String taskName) {

        this.sharedData = sharedData;

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // Paylaşılan veriye erişerek işi gerçekleştirme

        int data = sharedData.getData();

        System.out.println(taskName + " tarafından paylaşılan veri: " + data);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}


class SharedData {

    private int data;


    public SharedData() {

        this.data = 100;

    }


    public int getData() {

        return data;

    }

}

Bu örnekte, SharedData adında bir sınıf oluşturduk ve bu sınıf paylaşılan bir veri tutuyor. İş parçacığı havuzunda çalışan her iş parçacığı, SharedData nesnesine erişerek veriyi alıyor ve kullanıyor. Bu sayede iş parçacıkları arasında veri paylaşımı gerçekleştirilmiş oluyor.


ExecutorService, iş parçacığı havuzu yönetimini kolaylaştıran bir araçtır. Farklı senaryolara göre iş parçacığı havuzunu yapılandırabilir ve işleri yönetebilirsiniz. Bu sayede, çoklu görev yürütme, performans iyileştirmesi, senkronizasyon ve veri paylaşımı gibi iş parçacığı yönetimi konularında kolaylık sağlar. Yine de, iş parçacığı sayısını ve kaynak kullanımını dikkatli bir şekilde yönetmek önemlidir. Ayrıca, senkronizasyon araçlarını ve veri paylaşımı stratejilerini doğru şekilde kullanarak uygulamanızın doğruluğunu sağlamalısınız.


Senaryo 7: İş Parçacığı Havuzunda İşleri İptal Etme


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // İşleri havuza gönderme ve Future nesnelerini alıma

        Future<?> future1 = executor.submit(new Task());

        Future<?> future2 = executor.submit(new Task());


        // İşleri iptal etme

        future1.cancel(true);

        future2.cancel(true);


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        while (!Thread.currentThread().isInterrupted()) {

            // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

        }

        System.out.println(Thread.currentThread().getName() + " işi iptal edildi.");

    }

}

Bu örnekte, submit() yöntemi kullanılarak işler havuza gönderilir ve her bir işin sonucunu temsil eden Future nesneleri alınır. Ardından, cancel() yöntemi ile işler iptal edilir. cancel(true) parametresi, işin çalıştırıldığı iş parçacığına iptal sinyali gönderir.


Senaryo 8: İş Parçacığı Havuzunda İstisnaları Yakalama


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // İşleri havuza gönderme

        executor.execute(new Task());

        executor.execute(new Task());


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        try {

            // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

            throw new Exception("Bir istisna oluştu.");

        } catch (Exception e) {

            System.err.println(Thread.currentThread().getName() + " işinde hata oluştu: " + e.getMessage());

        }

    }

}

Bu örnekte, iş parçacığı havuzunda çalıştırılan her işin içinde bir istisna oluşturuyoruz. try-catch bloğu içinde istisnayı yakalayarak hatayı işliyoruz. System.err.println() yöntemiyle hata mesajını konsola yazdırıyoruz.


ExecutorService, Java'da iş parçacığı yönetimini kolaylaştıran güçlü bir araçtır. Çeşitli senaryolara uygun olarak iş parçacığı havuzunu yapılandırabilir ve işleri yönetebilirsiniz. Bu sayede, çoklu görev yürütme, performans iyileştirmesi, senkronizasyon, veri paylaşımı ve iş iptali gibi iş parçacığı yönetimi konularında kolaylık sağlar. Ancak, iş parçacığı sayısını, kaynak kullanımını ve hata yönetimini dikkatli bir şekilde ele almanız önemlidir.


ExecuterService mülakat soruları ve cevapları


İşte ExecutorService ile ilgili mülakat soruları ve cevapları:


Soru 1: ExecutorService nedir?


Cevap: ExecutorService, Java'nın java.util.concurrent paketinde yer alan bir arayüzdür. İş parçacığı havuzunu yönetmek ve iş parçacığı tabanlı çoklu görev yürütmek için kullanılır. ExecutorService, yüksek düzeyde bir arayüz sağlar ve gelişmiş bir iş parçacığı yönetimi sağlar.


Soru 2: ExecutorService'in avantajları nelerdir?


Cevap: ExecutorService kullanmanın bazı avantajları şunlardır:


Daha iyi performans: İş parçacığı havuzu kullanarak çoklu görevleri eşzamanlı olarak yürütebilir ve performansı artırabilirsiniz.

Kaynak yönetimi: ExecutorService, iş parçacıklarının oluşturulmasını ve sonlandırılmasını otomatik olarak yönetir. Bu sayede, kaynakların etkin bir şekilde kullanılmasını sağlar ve hataları en aza indirir.

İş parçacıkları arasındaki iletişimi kolaylaştırır: ExecutorService, iş parçacıkları arasında iletişim ve senkronizasyon için hazır araçlar sağlar. Bu sayede, iş parçacıkları arasında veri paylaşımı veya senkronizasyonu kolayca gerçekleştirebilirsiniz.

Soru 3: ExecutorService'in dezavantajları nelerdir?


Cevap: ExecutorService'in bazı dezavantajları şunlar olabilir:


Kaynak tükenmesi: Eğer iş parçacığı havuzunda çok fazla iş parçacığı oluşturursanız, sistem kaynaklarının tükenmesine neden olabilirsiniz. Bu durumda, performans yerine sistem performansı düşebilir.

İş parçacığı oluşturma maliyeti: Her iş parçacığı oluşturma işlemi bir maliyete sahiptir. Eğer çok küçük işler için sürekli olarak yeni iş parçacıkları oluşturursanız, bu iş parçacığı oluşturma maliyeti zamanla artabilir.

Soru 4: ExecutorService ile nasıl iş parçacığı havuzu oluşturulur?


Cevap: ExecutorService ile iş parçacığı havuzu oluşturmak için Executors sınıfının yöntemlerini kullanabilirsiniz. Örneğin, newFixedThreadPool() yöntemi ile belirli bir boyutta (sabit) iş parçacığı havuzu oluşturabilirsiniz. newCachedThreadPool() yöntemi ile dinamik olarak boyutlandırılabilen bir iş parçacığı havuzu oluşturabilirsiniz. newSingleThreadExecutor() yöntemi ile sadece tek bir iş parçacığından oluşan bir havuz oluşturabilirsiniz.


Soru 5: ExecutorService ile işleri nasıl havuza gönderebiliriz?


Cevap: İşleri havuza göndermek için execute() veya submit() yöntemlerini kullanabilirsiniz. execute() yöntemi, Runnable nesnelerini kabul ederken, submit() yöntemi Runnable veya Callable nesnelerini kabul eder ve bir Future nesnesi döndürür.


Soru 6: ExecutorService ile bir işin sonucunu nasıl elde edebiliriz?


Cevap: submit() yöntemi ile gönderilen işlerin sonucunu temsil eden Future nesneleri elde edilebilir. Future nesneleri, get() yöntemi kullanılarak işin sonucunu almanızı sağlar. get() yöntemi iş tamamlanana kadar bekler ve sonucu döndürür.


Soru 7: ExecutorService ile işleri nasıl iptal edebiliriz?


Cevap: submit() yöntemi ile gönderilen işlerin iptal edilmesi için Future nesnelerinin cancel() yöntemi kullanılır. cancel() yöntemi ile işe iptal sinyali gönderilir ve iş parçacığı içinde çalışan işin iptal edilmesi sağlanır.


Soru 8: ExecutorService ile iş parçacığı havuzunu nasıl kapatırız?


Cevap: shutdown() veya shutdownNow() yöntemlerini kullanarak iş parçacığı havuzunu kapatabilirsiniz. shutdown() yöntemi, iş parçacığı havuzuna yeni işlerin kabul edilmesini durdurur ve havuzdaki mevcut işlerin tamamlanmasını bekler. shutdownNow() yöntemi ise yeni işlerin kabul edilmesini durdurur ve havuzdaki tüm işleri iptal eder.


Bu mülakat soruları ve cevapları, ExecutorService ile ilgili temel kavramları ve kullanım senaryolarını kapsamaktadır. ExecutorService'in iş parçacığı yönetimi ve çoklu görev yürütme konularında ne kadar bilgi sahibi olduğunuzu ölçmek için kullanılabilir.


Soru 1: ExecutorService ile submit() ve execute() yöntemleri arasındaki fark nedir?


Cevap: ExecutorService'in submit() yöntemi, Runnable veya Callable nesnelerini kabul eder ve bir Future nesnesi döndürür. Bu Future nesnesi, işin sonucunu temsil eder ve get() yöntemi ile sonuç alınabilir. Öte yandan, execute() yöntemi sadece Runnable nesnelerini kabul eder ve işin sonucunu döndürmez. Yani, execute() yöntemi daha basit bir şekilde işi havuza gönderirken, submit() yöntemi daha esneklik sağlar ve işin sonucunu elde etmeyi mümkün kılar.


Soru 2: ExecutorService ile bir işin tamamlanmasını nasıl bekleyebiliriz?


Cevap: Future nesnelerini kullanarak bir işin tamamlanmasını bekleyebilirsiniz. submit() yöntemi ile gönderilen işlerin sonucunu temsil eden Future nesneleri elde edilebilir. Future nesnelerinin get() yöntemini kullanarak işin tamamlanmasını bekleyebilirsiniz. get() yöntemi, iş tamamlanana kadar bekler ve sonucu döndürür. Eğer birden fazla Future nesnesi varsa, CompletableFuture sınıfı veya CountDownLatch gibi senkronizasyon araçlarını kullanarak tüm işlerin tamamlanmasını bekleyebilirsiniz.


Soru 3: ExecutorService ile bir işin zamanlanmasını nasıl yapabiliriz?


Cevap: ScheduledExecutorService arayüzü, işlerin zamanlanmasını sağlar. Executors sınıfının newScheduledThreadPool() yöntemi kullanılarak bir ScheduledExecutorService nesnesi oluşturulabilir. Ardından, schedule() veya scheduleAtFixedRate() yöntemleri kullanılarak işler belirli bir süre sonra veya belirli aralıklarla çalıştırılabilir. schedule() yöntemi, işin belirli bir süre sonra başlatılmasını sağlar. scheduleAtFixedRate() yöntemi ise işin belirli aralıklarla düzenli olarak çalıştırılmasını sağlar.


Soru 4: ExecutorService'in shutdown() ve shutdownNow() yöntemleri arasındaki fark nedir?


Cevap: ExecutorService'in shutdown() yöntemi, iş parçacığı havuzuna yeni işlerin kabul edilmesini durdurur ve havuzdaki mevcut işlerin tamamlanmasını bekler. Yani, havuzdaki tüm işlerin bitirilmesini bekler, ancak işlemler tamamlanmadan program sonlanmaz. Diğer yandan, shutdownNow() yöntemi, iş parçacığı havuzuna yeni işlerin kabul edilmesini durdurur ve havuzdaki tüm işleri iptal eder. İşlemler anında sonlandırılır ve hangi işlerin tamamlandığına bakılmaksızın iptal edilir.


Soru 5: ExecutorService ile iş parçacığı havuzunu nasıl boyutlandırabiliriz?


Cevap: Executors sınıfının newFixedThreadPool() yöntemi ile sabit boyutlu bir iş parçacığı havuzu oluşturabilirsiniz. Bu yöntem belirli bir iş parçacığı sayısıyla bir havuz oluşturur ve her bir işi havuzdaki iş parçacıklarına dağıtır. Yine Executors sınıfının newCachedThreadPool() yöntemiyle dinamik boyutlandırılabilen bir iş parçacığı havuzu oluşturabilirsiniz. Bu yöntemde, ihtiyaç duyulan kadar iş parçacığı oluşturulur ve boşta kalan iş parçacıkları zamanla sonlandırılır.


Soru 6: ExecutorService'in yeni bir görevin başlatılmasını beklemek için hangi yöntemi kullanabiliriz?


Cevap: Future nesnelerini kullanarak yeni bir görevin başlatılmasını bekleyebilirsiniz. submit() yöntemi ile gönderilen işlerin sonucunu temsil eden Future nesnelerini alabilirsiniz. Future nesnelerinin get() yöntemini kullanarak yeni bir görevin tamamlanmasını bekleyebilirsiniz. get() yöntemi, yeni bir görev tamamlandığında sonucu döndürür.


Bu mülakat soruları ve cevapları, ExecutorService'in daha ileri düzeydeki konseptlerini ve kullanım senaryolarını kapsamaktadır. ExecutorService ile ilgili detaylı bilgi sahibi olmak ve mülakatlar için hazırlık yapmak için Java'nın java.util.concurrent paketinde yer alan diğer sınıfları (ScheduledExecutorService, CompletableFuture, Callable, vb.) da incelemeniz faydalı olacaktır.

Java Threads detaylı interview soruları ve cevapları



ChatGPT


Java Threads hakkında olası mülakat soruları ve cevapları aşağıdaki gibidir:


ChatGPT

Soru: Java'da bir thread nedir?


Cevap: Java'da bir thread, bir işletim sistemi süreci içinde bağımsız bir yürütme akışıdır. Her thread ayrı bir call stack'e sahiptir ve JVM'ye paralel programlama yeteneği sağlar.


Soru: Java'da bir thread nasıl oluşturulur?


Cevap: Java'da bir thread iki şekilde oluşturulabilir:


Thread sınıfını genişleterek.

Runnable interface'ini uygulayarak.

Soru: Thread sınıfının ve Runnable interface'inin farkı nedir?


Cevap: Thread sınıfını genişleterek bir sınıf yarattığınızda, Java'nın tek kalıtım sınırlaması nedeniyle başka bir sınıfı genişletemezsiniz. Ancak, Runnable interface'ini uygulayarak bir sınıf yarattığınızda, sınıfınız başka bir sınıfı genişletebilir.


Soru: Java'da threadlerin durumları nelerdir?


Cevap: Java'da threadlerin altı temel durumu vardır:


Yeni (New): Thread oluşturulmuş ama henüz başlamamış.

Çalışabilir (Runnable): Thread çalıştırılmak üzere hazır.

Çalışıyor (Running): Thread şu anda çalışıyor.

Engellendi (Blocked): Thread çalışmayı bekliyor çünkü bazı kaynaklara erişimini bekliyor.

Zaman aşımına uğradı (Timed waiting): Thread belirli bir süre beklemek zorunda.

Sonlandı (Terminated): Thread çalışmayı tamamladı.

Soru: Java'da bir thread nasıl durdurulur?


Cevap: Java'da bir threadi durdurmanın doğru yolu, thread'in normal olarak tamamlanmasını sağlamaktır. Bu genellikle thread'in kontrol ettiği bir durum değişkenini değiştirerek yapılır. Thread.stop() yöntemi kullanımı tehlikelidir ve artık önerilmez çünkü kaynakların tahsisini veya temizlenmesini düzgün bir şekilde kontrol etmez.


Soru: Thread.sleep() ve Thread.yield() arasındaki fark nedir?


Cevap: Thread.sleep() metodu, belirli bir süre için geçerli thread'in yürütmesini duraklatır. Diğer yandan, Thread.yield() metodu, geçerli thread'in CPU kullanımını bırakıp diğer thread'lerin yürütülmesini teşvik eder.


Soru: Deadlock nedir ve nasıl önlenir?


Cevap: Deadlock, iki veya daha fazla thread'in birbirini beklediği ve dolayısıyla hiçbirinin ilerlemeyeceği bir durumdur. Deadlock'ın önlenmesi, kaynaklara erişimin dikkatlice kontrol edilmesini gerektirir. Deadlock'ı önlemek için kullanılabilecek birkaç strateji vardır:


Dikkatli Kaynak Sıralaması: Kaynaklara erişim için belirli bir sıralama belirlemek ve tüm thread'lerin bu sıralamayı takip etmesini sağlamak.

Kaynakların Zaman Aşımı: Bir thread bir kaynağa belirli bir süre boyunca erişemezse, işlemi iptal etmek ve daha sonra tekrar denemek.

Deadlock Önleme Algoritmaları: Birden fazla thread'in aynı anda bir dizi kaynağa erişmesine izin veren özel algoritmalar (örneğin, Banker’s algorithm) kullanmak.

Soru: Java'da thread'ler nasıl senkronize edilir?


Cevap: Java'da thread'ler 'synchronized' anahtar kelimesi veya 'Lock' interface'i aracılığıyla senkronize edilir. 'Synchronized' anahtar kelimesi, aynı anda bir thread'in bir metod veya bir bloğa erişmesini sınırlar. 'Lock' interface'i daha esnek bir kilit mekanizması sağlar, özellikle birden fazla lock'un elde edildiği ve bırakıldığı karmaşık durumlar için.


Soru: Java'da 'volatile' anahtar kelimesi ne işe yarar?


Cevap: 'Volatile' anahtar kelimesi, Java'da bir değişkenin değerinin birden fazla thread tarafından kullanıldığında bellekte tutulacağını garanti eder. Bu, her thread'in son en son güncellemeyi gördüğünden emin olmasını sağlar. Bu, değişkenin değerinin farklı thread'ler arasında tutarlı olmasını sağlar.


Soru: Java'da 'wait()', 'notify()' ve 'notifyAll()' metodları ne işe yarar?


Cevap: 'Wait()', 'notify()' ve 'notifyAll()' metotları, Java'da bir nesnenin kilidini almak ve bırakmak için kullanılır. 'Wait()' metodu, bir thread'in bir nesnenin kilidini bırakmasını ve bir başka thread'in 'notify()' veya 'notifyAll()' metodu tarafından bildirim alana kadar beklemesini sağlar. 'Notify()' metodu, bir nesnenin kilidini bekleyen thread'lere bildirim gönderir ve 'notifyAll()' tüm bekleyen thread'lere bildirim gönderir.

Soru: 'synchronized' bloklar ve metotlar arasındaki fark nedir?


Cevap: 'synchronized' bloklar, belirli bir blok üzerinde senkronizasyon sağlarken, 'synchronized' metotlar, metodu çağırırken nesnenin tamamında senkronizasyon sağlar. 'Synchronized' bloklar daha fazla esneklik sağlar, çünkü belirli bir kısmın senkronize edilmesini sağlar, ancak 'synchronized' metotlar daha kolay ve daha güvenli olabilir.


Soru: Java'da 'ThreadLocal' sınıfının amacı nedir?


Cevap: 'ThreadLocal' sınıfı, her thread için ayrı bir değişken kopyası sağlar. Bu, her thread'in kendi bağımsız değişkenine sahip olmasını sağlar ve bu değişken diğer thread'ler tarafından erişilemez.


Soru: Java'da 'Daemon Thread' nedir?


Cevap: Java'da 'Daemon Thread', genellikle arka plan hizmetleri için kullanılan özel bir tür thread'dir. Bu tür bir thread, tüm non-daemon thread'ler sonlandığında JVM'nin durmasını engellemez.


Soru: Java'da 'Thread.join()' metodu ne işe yarar?


Cevap: 'Thread.join()' metodu, belirli bir thread'in tamamlanmasını bekler. Yani, 'thread.join()' çağrısı yapan thread, belirtilen thread'in tamamlanmasını bekler. Bu, bir thread'in bir diğerini beklemesi gereken durumlar için kullanışlıdır.


Soru: Java'da 'Thread.interrupt()' metodu ne işe yarar?


Cevap: 'Thread.interrupt()' metodu, belirli bir thread'e bir kesme talebi gönderir. Bu, thread'in uyandırılmasını veya yürütmesinin durdurulmasını talep etmek için kullanılır. Ancak, kesme talebi gönderilen thread'in bu talebi nasıl ele alacağına bağlıdır. İnterrupt talebi, genellikle bir thread'i bloklanmış veya bekleyen durumdan çıkarır.

Soru: Java'da 'ThreadGroup' nedir?


Cevap: 'ThreadGroup' Java'da bir özelliktir ki bu, belirli bir grup thread'i tek bir birim olarak düşünmemizi ve bu thread'lere topluca kontrol ve yönetim işlemleri yapmamızı sağlar. Bir 'ThreadGroup', belirli bir grup thread'i organize etmek, grup üzerinde yönetim işlemleri yapmak ve debug bilgilerini toplamak için kullanılır.


Soru: Java'da Concurrent Collections hakkında ne biliyorsunuz?


Cevap: Java'da Concurrent Collections, çoklu thread'lerin aynı anda veriye erişmesini ve veriyi değiştirmesini sağlayan bir dizi veri yapısıdır. 'java.util.concurrent' paketi, thread-safe collection sınıfları ve interface'leri içerir. Bu sınıflar, thread'lerin aynı anda veriye erişebilmesini sağlar ve dolayısıyla programın performansını artırır.


Soru: 'ReentrantLock' nedir ve nasıl kullanılır?


Cevap: 'ReentrantLock', bir thread'in aynı lock'u birden çok kez elde etmesine olanak sağlayan bir kilit mekanizmasıdır. Bu, aynı thread içinde birden çok method'un aynı kaynağı lock etme ihtiyacı olduğunda kullanışlıdır. 'ReentrantLock' daha karmaşık kilitlilik senaryolarında 'synchronized' anahtar kelimesine göre daha fazla esneklik sağlar.


Soru: 'Semaphore' sınıfı ne işe yarar?


Cevap: 'Semaphore', genellikle belirli bir kaynağa aynı anda kaç thread'in erişebileceğini kontrol etmek için kullanılır. Semaphores, kaynakların sınırlı sayıda olduğu durumlarda, örneğin veri tabanı bağlantıları gibi, kullanışlıdır.


Soru: Java'da 'Futures' ve 'Callable' nedir?


Cevap: 'Callable' interface'i, bir sonuç döndürme yeteneğine sahip olan ve bir 'Exception' atabilen bir task'ı temsil eder. 'Future' ise, 'Callable' tarafından yürütülen bir işlemin sonucunu temsil eder. 'Future.get()' metodu, işlem tamamlanana kadar bloklanır ve sonra sonucu döndürür. Bu, işlem sonuçlarının alınmasını ve işlemlerin zamanlamasını kontrol etmeyi kolaylaştırır.

Soru: Java'da 'CountDownLatch' nedir?

Cevap: 'CountDownLatch', bir veya daha fazla thread'in belirli bir işlemin tamamlanmasını beklemesini sağlar. İşlem tamamlanana kadar 'CountDownLatch' bekleyen thread'leri bloklar. İşlem tamamlandığında latch sayısı sıfıra düşer ve tüm bekleyen thread'ler serbest bırakılır.


Soru: Java'da 'CyclicBarrier' nedir?

Cevap: 'CyclicBarrier', belirli bir thread sayısına ulaşıldığında tetiklenir. Buna bir "barrier point" denir. Tüm thread'ler bu noktada birbirlerini bekler ve ardından birlikte ilerlerler. Bu, belirli bir görevin farklı aşamalarında senkronizasyon gerektiren durumlar için kullanışlıdır.


Soru: Java'da 'Executor' ve 'ExecutorService' arasındaki fark nedir?

Cevap: 'Executor' interface'i, yeni thread'lerin oluşturulmasını ve başlatılmasını yönetir. 'ExecutorService' ise 'Executor' interface'ini genişletir ve thread havuzu yönetimi, thread'lerin durumunu kontrol etme ve thread'lerin düzgün bir şekilde kapatılmasını sağlar.


Soru: Java'da 'ThreadFactory' nedir?

Cevap: 'ThreadFactory', yeni thread'ler oluşturmak için kullanılan bir arayüzü tanımlar. 'ThreadFactory', bir uygulamanın nasıl yeni thread'ler oluşturacağını özelleştirmesine olanak sağlar, örneğin thread'in adını, önceliğini veya 'daemon' durumunu belirler.


Soru: 'Atomic' sınıflar nelerdir ve ne işe yararlar?

Cevap: 'Atomic' sınıflar, atomik şekilde (yani, tek bir işlem olarak) birden çok işlemi gerçekleştirmeyi sağlarlar. Bu, birden fazla thread'in aynı değişkeni değiştirmeye çalıştığında oluşabilecek yarış koşullarını önler. Java'da 'AtomicInteger', 'AtomicLong', 'AtomicBoolean', gibi atomic sınıflar bulunmaktadır.


Bu sorular ve yanıtlar, Java thread'leri hakkında bir mülakatta karşılaşılabilecek genel konuları kapsamaktadır. Ancak, mülakat soruları, mülakat yapan kişi veya şirketin ihtiyaçlarına bağlı olarak değişiklik gösterebilir.

Soru: 'ScheduledExecutorService' nedir ve ne işe yarar?

Cevap: 'ScheduledExecutorService', belirli bir gecikme sonrasında veya belirli bir süre boyunca düzenli aralıklarla komutları yürütmeyi sağlayan bir ExecutorService'dir. 'schedule()', 'scheduleAtFixedRate()', ve 'scheduleWithFixedDelay()' gibi metotları içerir.


Soru: 'Synchronization' ve 'Lock' arasındaki fark nedir?

Cevap: 'Synchronization' ve 'Lock' her ikisi de birden fazla thread'in aynı anda paylaşılan verilere erişimini kontrol etme mekanizmalarıdır. Ancak, 'Lock' interface'i, 'synchronized' anahtar kelimesine göre daha fazla esneklik ve kontrol sağlar. 'Lock' mekanizması, thread'ler arasında adil erişimi sağlayabilir, kilit elde etme ve bırakma işlemlerini daha esnek hale getirebilir ve kilit elde etmeyi beklerken thread'in kesilmesine izin verebilir.


Soru: Java'da 'Thread Pool' nedir ve nasıl kullanılır?

Cevap: 'Thread Pool', bir işlemi yürütmek için kullanılabilen sınırlı sayıda thread'i içeren bir havuzdur. 'ThreadPool' kullanarak, aynı anda çalıştırılabilecek thread sayısını sınırlayabilir ve böylece sistem kaynaklarını daha etkili bir şekilde yönetebiliriz. Java'da 'ExecutorService' kullanarak 'Thread Pool' oluşturabiliriz.


Soru: 'Thread Starvation' nedir?

Cevap: 'Thread Starvation', bir veya daha fazla thread'in CPU zaman dilimine erişememesi durumudur. Bu genellikle öncelikli thread'lerin düşük öncelikli thread'leri sürekli olarak engellemesi sonucu olur. Uzun süreli 'Starvation', uygulamanın performansını önemli ölçüde etkileyebilir.


Soru: 'Thread Dump' nedir?

Cevap: 'Thread Dump', bir Java uygulamasında çalışan tüm thread'lerin anlık durum bilgisini içerir. 'Thread Dump' genellikle bir uygulamanın hata ayıklaması için kullanılır, çünkü mevcut thread'lerin durumunu, stack trace'lerini ve diğer bilgileri gösterir.

Java'da Multithreading ve Concurrency Soruları ve Cevapları - Martin Mois Çevirisi - Devam edecek...


Yazının orjinaline buradan ulaşabilirsiniz.

Eşzamanlılık (Concurrency) teriminden ne anlıyoruz?

Concurrency, bir programın birkaç hesaplamayı aynı anda yürütme yeteneğidir. Bu, hesaplamaları bir makinenin kullanılabilir CPU çekirdeklerine veya hatta aynı ağ içindeki farklı makinelere dağıtarak elde edilebilir.

İşlemler(Process) ve iş parçacıkları(Threads) arasındaki fark nedir?

İşlemler, işletim sistemi tarafından sağlanan ve kendi özel kaynaklarına (ör. bellek, açık dosyalar vb.) sahip bir yürütme ortamıdır. İş parçacıkları, süreçlerin aksine, bir işlem içinde yaşar ve kaynaklarını (bellek, açık dosyalar vb.) işlemin diğer İş parçacıkları ile paylaşır. Kaynakları farklı İş parçacıkları arasında paylaşma yeteneği, İş parçacıkları performansın önemli bir gereksinim olduğu tasklar için daha uygun hale getirir.

Java'da, process ve thread nedir?

Java'da İşlemler (process), çalışan bir Java Sanal Makinesi'ne (JVM) karşılık gelirken, İş parçacıkları (threads) JVM içinde yaşar ve çalışma zamanında Java uygulaması tarafından dinamik olarak oluşturulabilir ve durdurulabilir.

Zamanlayıcı (Scheduler) nedir?

Zamanlayıcı, işlemlerin ve iş parçacıklarının işlemci veya bazı G/Ç kanalları gibi bazı sınırlı kaynaklara erişimini yöneten bir zamanlama algoritmasının uygulanmasıdır. Çoğu zamanlama algoritmasının amacı, her işlemin/thread'ın özel olarak istenen kaynağa erişmek için uygun bir zaman çerçevesi almasını garanti eden mevcut işlemler/iş parçacıkları için bir tür yük dengeleme sağlamaktır.

Bir Java programında en az kaç thread vardır?

Her Java programı ana(main) thread içinde yürütülür; dolayısıyla her Java uygulamasının en az bir thread vardır.

Bir Java uygulaması mevcut thread'a nasıl erişebilir?

Geçerlit hread'a, JDK sınıfı java.lang.Thread'in currentThread() statik yöntemi çağrılarak erişilebilir:



Her Java thread'ın hangi özellikleri vardır?

Her Java thread aşağıdaki özelliklere sahiptir:
• JVM içinde benzersiz olan long türünde bir tanımlayıcı (identifier)
• String türünde bir ad (name)
• int türünde bir öncelik(priority)
• java.lang.Thread.State türünde bir durum (state)
• thread'ın ait olduğu bir thread grubu (thread group)

Thread gruplarının amacı nedir?

Her thread bir thread grubuna aittir. JDK sınıfı java.lang.ThreadGroup, tüm thread grubunu işlemek için bazı yöntemler sağlar. Bu yöntemlerle, örneğin bir grubun tüm iş parçacıklarını kesebilir veya maksimum önceliklerini ayarlayabiliriz.

Bir thread'ın hangi durumları olabilir ve her bir durumun anlamı nedir?

YENİ (NEW): Henüz başlamamış bir thread bu durumdadır.

ÇALIŞTIRILABİLİR(RUNNABLE): Java sanal makinesinde çalışan bir thread bu durumdadır.

BLOCKED: Bir monitör kilidi beklerken bloke edilmiş bir thread bu durumdadır.

BEKLEMEKTE(WAITING): Başka bir thread'ın belirli bir eylemi gerçekleştirmesini süresiz olarak bekleyen bir thread bu durumdadır.

TIMED_WAITING: Belirli bir bekleme süresi kadar başka bir thread'ın bir eylem gerçekleştirmesini bekleyen bir thread bu durumdadır.

SONLANDIRILDI(TERMINATED): Çıkmış olan bir thread bu durumdadır.

Bir thread'ın önceliğini nasıl belirleriz?

Bir thread'ın önceliği, setPriority(int) yöntemi kullanılarak belirlenir. Önceliği maksimum değere ayarlamak için Thread.MAX_PRIORITY sabitini ve minimum değere ayarlamak için Thread.MIN_PRIORITY sabitini kullanırız, çünkü bu değerler farklı JVM uygulamaları arasında farklılık gösterebilir.

Java'da bir thread nasıl oluşturulur?

Temel olarak, Java'da bir thread oluşturmanın iki yolu vardır.

İlki, JDK sınıfını java.lang.Thread genişleten bir sınıf yazmak ve bunun yöntemini start() olarak çağırmak:


İkinci yol, java.lang.Runnable arabirimini uygulamak ve bu uygulamayı java.lang.Thread'in yapıcısına bir parametre olarak iletmektir:


1.13 Neden bir thread, yöntemi stop() çağrılarak durdurulmamalıdır?

Java.lang.Thread'in kullanımdan kaldırılan stop() yöntemi kullanılarak bir thread durdurulmamalıdır, çünkü bu yöntemin çağrılması thread'ın edindiği tüm monitörlerin kilidini açmasına neden olur. Serbest bırakılan kilitlerden biri tarafından korunan herhangi bir nesne tutarsız bir durumdaysa, bu durum diğer tüm iş parçacıkları tarafından görülebilir. Bu, diğer iş parçacıkları bu tutarsız nesneyi çalıştırdığında keyfi davranışa neden olabilir.

Bir Thread'i nasıl durdururuz?

Java'da bir thread'i durdurmak için Thread.stop() metodu kullanılabilir, ancak bu yöntem artık önerilmez. Bunun yerine, bir thread'in çalışmasını durdurmak için Thread.interrupt() metodu kullanılmalıdır. Bu yöntem, hedef thread'in interrupt flag'ini ayarlar ve thread uygun bir noktada kendini durdurabilir.

Aşağıdaki örnekte, ana thread bir çalışan thread'i oluşturur ve birkaç saniye bekledikten sonra interrupt() yöntemini kullanarak çalışan thread'in çalışmasını durdurur.


Bir thread'i iki kez başlatmak mümkün mü?

Hayır, start() yöntemini çağırarak bir thread başlattıktan sonra, ikinci bir start() çağrısı bir IllegalThreadStateException oluşturur.

Aşağıdaki kodun çıktısı nedir?


Yukarıdaki kod, "myThread" değil, "main" çıktısını üretir. main() metodunun 2. satırında görüldüğü gibi start() yerine yanlışlıkla run() metodunu çağırıyoruz. Bu nedenle, yeni bir thread başlatılmaz, ancak ana thread içinde run() yöntemi yürütülür.

Arka plan programı (Daemon) thread nedir?

Daemon thread, JVM durup durmamaya karar verdiğinde yürütme durumu değerlendirilmeyen bir thread'dır. JVM, tüm kullanıcı threadleri (deamon threadlerin aksine) sonlandırıldığında durur. Bu nedenle, deamon iş parçacıkları, tüm kullanıcı iş parçacıkları durur durmaz thread JVM tarafından durdurulduğu için, örneğin izleme işlevini uygulamak için kullanılabilir:


Yukarıdaki örnek uygulama, arka plan programı thread sonsuz while döngüsünde arka planda çalışmaya devam etmesine rağmen sonlandırılıyor.

Başlatıldıktan sonra normal bir kullanıcı thread'ı arka plan programı(Deamon)thread'a dönüştürmek mümkün müdür?

Bir kullanıcı thread başlatıldıktan sonra arka plan programı thread'a dönüştürülemez. Halihazırda çalışan bir thread örneğinde thread.setDaemon(true) yöntemini çağırmak, bir IllegalThreadStateException'a neden olur.

Meşgul beklemekten (Busy Waiting) ne anlıyoruz?

Meşgul bekleme, thread'ın/işlemin işlemciyi işgal etmesine izin veren bazı aktif hesaplamalar yaparak bir olayı(event) bekleyen uygulamalar anlamına gelir, ancak programlayıcı tarafından ondan kaldırılabilir. Meşgul beklemeye bir örnek, bekleme zamanını, zamanın belirli bir noktasına ulaşılana kadar tekrar tekrar o anki zamanı belirleyen bir döngü içinde geçirmek olabilir:


Meşgul beklemeyi nasıl önleyebiliriz?

Meşgul beklemeyi önlemenin bir yolu, mevcut thread'ı belirli bir süre uyku moduna geçirmektir. Bu, java.lang.Thread.sleep(long) yöntemini çağırarak, uyku moduna geçen milisaniye sayısını bağımsız değişken olarak ileterek yapılabilir.

Gerçek zamanlı (Real time) işleme için Thread.sleep() kullanabilir miyiz?

Thread.sleep(long) çağrısına geçen milisaniye sayısı, yalnızca zamanlayıcı için geçerli thread'ın ne kadar süreyle yürütülmesi gerekmediğinin bir göstergesidir. Zamanlayıcı, gerçek uygulamaya bağlı olarak thread'ın birkaç milisaniye önce veya sonra yeniden yürütülmesine izin verebilir. Bu nedenle, gerçek zamanlı işleme için Thread.sleep() çağrısı kullanılmamalıdır.

Thread.sleep() kullanılan uyku moduna alınmış bir iş parçacığı, süresi dolmadan nasıl uyandırılabilir?

java.lang.Thread'in interrupt() yöntemi uyuyan bir iş parçacığını kesintiye uğratır. Thread.sleep() çağrılarak uyku moduna alınan kesintiye uğramış iş parçacığı, bir InterruptedException tarafından uyandırılır:


Bir thread interrupt olmuşsa sorgusu nasıl olabilir? 

İş parçacığı, Thread.sleep() gibi bir InterruptedException oluşturacak bir yöntem içinde değilse, iş parçacığı,  java.lang.Thread'den miras aldığı Thread.interrupted() statik yöntemini veya isInterrupted() yöntemini çağırarak kesintiye uğrayıp uğramadığını sorgulayabilir..

Bir InterruptedException nasıl ele alınmalıdır?

sleep() ve join() gibi yöntemler, caller'a bu iş parçacığını başka bir iş parçacağının kesintiye uğrattığını bildirmek için bir InterruptedException atar. Çoğu durumda bu, mevcut iş parçacığına mevcut hesaplamalarını durdurmasını ve beklenmedik bir şekilde bitirmesini söylemek için yapılır. Bu nedenle, istisnayı yakalayarak görmezden gelmek ve sadece konsola veya bazı günlük dosyalarına kaydetmek, genellikle bu tür bir istisnayı ele almanın uygun yolu değildir. Bu özel durumla ilgili sorun, Runnable arabiriminin run() yönteminin run() öğesinin herhangi bir istisna atmasına izin vermemesidir. Yani sadece yeniden atmak yardımcı olmuyor. Bu, run() uygulamasının bu kontrol edilen istisnayı kendisi halletmesi gerektiği anlamına gelir ve bu genellikle istisnanın yakalanmasına ve yok sayılmasına yol açar.


Bir alt iş parçacığı başlattıktan sonra, alt iş parçacığının sonlandırılması için ana iş parçacığında nasıl bekleyeceğiz?

Bir iş parçacığının sonlandırılmasını beklemek, iş parçacığının örnek değişkeninde birleştirme() yöntemi çağrılarak yapılır:



Aşağıdaki programın çıktısı nedir?


Yukarıdaki kodun çıktısı "false". MyDaemonThread örneği bir daemon iş parçacığı olmasına rağmen, join() çağrısı, ana iş parçacığının arka plan programı iş parçacığının yürütülmesi bitene kadar beklemesine neden olur. Dolayısıyla, iş parçacığı örneğinde isAlive() öğesinin çağrılması, arka plan programı iş parçacığının artık çalışmadığını gösterir.

Yakalanmamış bir özel durum run() yönteminden ayrıldığında ne olur? 

Run() yönteminden denetlenmeyen bir istisna kaçabilir. Bu durumda, iş parçacığı Java Sanal Makinesi tarafından durdurulur. UncaughtException Handler arayüzünü bir istisna işleyici olarak uygulayan bir örneği kaydederek bu istisnayı yakalamak mümkündür. Bu, JVM'ye iş parçacığının kendisinde kayıtlı belirli bir işleyici olmaması durumunda sağlanan işleyiciyi kullanmasını söyleyen Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler) statik yöntemini çağırarak veya setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler) işlevini çağırarak yapılır. iş parçacığı örneğinin kendisidir.

Kapatma kancası nedir? (Shutdown Hook)

Kapatma kancası, JVM kapandığında yürütülen bir iş parçacığıdır. Runtime örneğinde addShutdownHook(Runnable) çağrılarak kaydedilebilir:

Eşzamanlı(synchronized) anahtar kelime hangi amaçlarla kullanılıyor?

Bir kaynağa, bazı statik değerler veya bazı dosya referansları gibi özel erişim uygulamanız gerektiğinde, özel kaynakla çalışan kod, senkronize edilmiş bir blokla kucaklanabilir:


Eşzamanlı bir yöntem (synchronized method) hangi içsel kilidi elde eder?

Eşzamanlı bir yöntem, o yöntemin nesnesi için içsel kilidi alır ve yöntem geri döndüğünde onu serbest bırakır. Yöntem bir istisna oluştursa bile, içsel kilit serbest bırakılır. Bu nedenle, senkronize edilmiş bir yöntem aşağıdaki koda eşittir:

Bir yapıcı (constructor) senkronize edilebilir mi?

Hayır, bir oluşturucu senkronize edilemez. Bunun bir sözdizimi hatasına yol açmasının nedeni, yalnızca inşa edilen iş parçacığının oluşturulan nesneye erişiminin olması gerektiği gerçeğidir.


İlkel değerler(primitive values) içsel kilitler(intrinsic locks) için kullanılabilir mi?

Hayır, ilkel değerler içsel kilitler için kullanılamaz.

İçsel kilitler yeniden girişli midir?

Evet, gerçek kilitlere aynı iş parçacığı tarafından tekrar tekrar erişilebilir. Aksi takdirde, bir kilit alan kod, daha önce edindiği bir kilidi yanlışlıkla almaya çalışmamasına dikkat etmelidir.

Atomik bir işlemden ne anlıyoruz?

Atomik bir işlem, tamamen yürütülen veya hiç yürütülmeyen bir işlemdir.

C++ deyimi atomik mi?

Hayır, bir tamsayı değişkenin artırımı birden fazla işlemden oluşur. Önce c'nin mevcut değerini yüklemeli, artırmalı ve son olarak yeni değeri geri kaydetmeliyiz. Bu artışı gerçekleştiren mevcut iş parçacığı, bu üç adımdan herhangi biri arasında kesintiye uğrayabilir, dolayısıyla bu işlem atomik değildir.


Java'da hangi işlemler atomiktir?

Java dili, atomik olan ve bu nedenle eşzamanlı iş parçacıklarının her zaman aynı değeri görmesini sağlamak için kullanılabilecek bazı temel işlemler sağlar:

• Referans değişkenlere ve ilkel değişkenlere yönelik okuma ve yazma işlemleri (long ve double hariç)

• volatile olarak bildirilen tüm değişkenler için okuma ve yazma işlemleri

Aşağıdaki uygulama iş parçacığı açısından güvenli(thread-safe) mi?


Yukarıdaki kod iş parçacığı için güvenli değil. JIT derleyicisi, senkronize blok içinde örneğin değerini bir kez daha kontrol etse de (performans nedenleriyle), bytecode'u, örneğe yapılan başvuru yapıcı yürütmeyi bitirmeden önce ayarlanacak şekilde yeniden düzenleyebilir. Bu, getInstance() yönteminin tamamen başlatılmamış olabilecek bir nesne döndürdüğü anlamına gelir. Kodu iş parçacığı açısından güvenli hale getirmek için, örnek değişkeni için Java 5'ten beri volatile anahtar sözcüğü kullanılabilir.

Uçucu olarak işaretlenen değişkenler, yalnızca nesnenin yapıcısı yürütmeyi tamamen bitirdiğinde diğer iş parçacıkları tarafından görünür hale gelir.

Kilitlenmeden(deadlock) ne anlıyoruz?

Kilitlenme, iki (veya daha fazla) iş parçacığının diğer iş parçacığında kilitlediği bir kaynağı serbest bırakmak için beklediği, iş parçacığının kendisinin diğer iş parçacığının beklediği bir kaynağı kilitlediği bir durumdur: 

İş Parçacığı 1: A kaynağını kilitler , B kaynağını bekler

İş Parçacığı 2: B kaynağını kilitler, A kaynağını bekler


Kilitlenme durumu için gereksinimler nelerdir?

Genel olarak bir kilitlenme için aşağıdaki gereksinimler tanımlanabilir:

• Karşılıklı dışlama (Mutual exclusion): Herhangi bir zamanda yalnızca bir iş parçacığı tarafından erişilebilen bir kaynak vardır.

• Kaynak tutma(Resource holding:): Bir kaynağı kilitlerken, iş parçacığı başka bir özel kaynak üzerinde başka bir kilit elde etmeye çalışır.

• Önleme yok(No preemption): Bir iş parçacığının kilidi belirli bir süre boyunca tutması durumunda kaynağı serbest bırakan bir mekanizma yoktur.

• Dairesel bekleme(Circular wait): Çalışma zamanı sırasında, kilitlediği bir kaynağı serbest bırakmak için iki (veya daha fazla) iş parçacığının diğer iş parçacığında beklediği bir takımyıldız oluşur.

Kilitlenmeleri tamamen önlemek mümkün mü?

Kilitlenmeleri önlemek için kilitlenme gereksinimlerinden birinin (veya daha fazlasının) ortadan kaldırılması gerekir:

• Karşılıklı dışlama: Bazı durumlarda, iyimser kilitleme kullanarak karşılıklı dışlamayı önlemek mümkündür.

• Kaynak tutma: Bir iş parçacığı, tüm özel kilitleri elde etmeyi başaramadığı zaman, tüm özel kilitlerini serbest bırakabilir.

• Önleme yok: Özel bir kilit için bir zaman aşımı kullanmak, kilidi belirli bir süre sonra serbest bırakır.

• Döngüsel bekleme: Tüm özel kilitler aynı sıradaki tüm iş parçacıkları tarafından elde edildiğinde döngüsel bekleme gerçekleşmez.

Bir kilitlenme tespiti uygulamak mümkün müdür?

Tüm özel kilitler izlendiğinde ve yönlendirilmiş bir grafik olarak modellendiğinde, bir kilitlenme tespit sistemi, kilitlediği bir kaynağı serbest bırakmak için her biri diğer iş parçacığında bekleyen iki iş parçacığını arayabilir. Bekleyen iş parçacıkları daha sonra bir tür istisna tarafından diğer iş parçacığının beklediği kilidi serbest bırakmaya zorlanabilir.

Canlı kilit (livelock) nedir?

Canlı kilit, iki veya daha fazla iş parçacığının başka bir iş parçacığından kaynaklanan bir eyleme yanıt vererek birbirini bloke ettiği bir durumdur. İki veya daha fazla iş parçacığının belirli bir durumda beklediği bir kilitlenme durumunun aksine, canlı kilitlemeye katılan iş parçacıkları durumlarını normal işlerinde ilerlemeyi engelleyecek şekilde değiştirir. Bir örnek, iki iş parçacığının iki kilit elde etmeye çalıştığı, ancak ikinci kilidi elde edemeyince elde ettikleri bir kilidi serbest bıraktığı bir durum olabilir. Artık her iki iş parçacığı aynı anda ilk iş parçacığını almaya çalışabilir. Yalnızca bir iş parçacığı başarılı olduğu için, ikinci iş parçacığı ikinci kilidi elde etmeyi başarabilir. Şimdi her iki iş parçacığı da iki farklı kilide sahiptir, ancak her ikisi de her iki kilide de sahip olmak istedikleri için kilitlerini serbest bırakırlar ve baştan tekrar denerler. Bu durum şimdi tekrar tekrar olabilir.

İş parçacığı açlığından(thread starvation) ne anlıyoruz?

Daha düşük önceliğe sahip iş parçacıkları, daha yüksek önceliğe sahip iş parçacıklarından daha az yürütme süresi alır. Daha düşük önceliğe sahip iş parçacıkları uzun süreli hesaplamalar yaptığında, bu iş parçacıklarının hesaplamalarını tam zamanında bitirmek için yeterli zamanları olmayabilir. Daha yüksek önceliğe sahip iş parçacıkları hesaplama sürelerini çaldığından "açlıktan ölüyor" gibi görünüyorlar.

Senkronize bir blok iş parçacığının aç kalmasına neden olabilir mi?

İş parçacıklarının senkronize bir bloğa girebileceği sıra tanımlanmamıştır. Yani teorik olarak, birçok thread'in senkronize bir bloğa girişi beklemesi durumunda, bazı thread'lerin diğer thread'lerden daha uzun süre beklemesi gerekebilir. Dolayısıyla işlerini zamanında bitirmek için yeterli hesaplama süresine sahip değiller.

Yarış durumu(race condition) teriminden ne anlıyoruz?

Bir yarış koşulu, bazı çoklu iş parçacıklı uygulamanın sonucunun, katılan iş parçacıklarının tam zamanlama davranışına bağlı olduğu takımyıldızları tanımlar. Çoğu durumda bu tür bir davranışa sahip olmak istenmez, bu nedenle yarış durumu terimi aynı zamanda eksik iş parçacığı senkronizasyonundan kaynaklanan bir hatanın farklı sonuçlara yol açtığı anlamına gelir. Bir yarış koşulu için basit bir örnek, bir tamsayı değişkeninin iki eşzamanlı iş parçacığı tarafından artırılmasıdır. İşlem birden fazla tek ve atomik işlemden oluştuğu için, her iki iş parçacığı aynı değeri okur ve artırır. Bu eşzamanlı artıştan sonra, tamsayı değişkeninin miktarı iki değil, yalnızca bir artırılır.

Adil kilitlerden(fair locks) ne anlıyoruz?

Adil bir kilit, engeli bazı özel kaynaklara aşan bir sonraki iş parçacığını seçerken iş parçacıklarının bekleme süresini hesaba katar. Adil kilidin örnek bir uygulaması Java SDK tarafından sağlanır: java.util.concurrent.locks.ReentrantLock. Boole bayrağı true olarak ayarlanmış yapıcı kullanılırsa, ReentrantLock en uzun süre bekleyen iş parçacığına erişim sağlar.

Her nesnenin java.lang.Object'ten miras aldığı hangi iki yöntem, basit bir üretici/tüketici senaryosu uygulamak için kullanılabilir?

Bir çalışan iş parçacığı mevcut görevini bitirdiğinde ve yeni görevler için sıra boş olduğunda, kuyruk nesnesinde içsel bir kilit elde ederek ve wait() yöntemini çağırarak işlemciyi serbest bırakabilir. İş parçacığı, kuyruğa yeni bir görev koyan ve sıra nesnesinde yeniden aynı iç kilidi alan ve üzerinde notify() öğesini çağıran bazı üretici iş parçacığı tarafından uyandırılacaktır.

notify() ve notifyAll() arasındaki fark nedir?

Her iki yöntem de wait() çağrılarak kendilerini uyku moduna almış bir veya daha fazla iş parçacığını uyandırmak için kullanılır. notify() yalnızca bekleyen evrelerden birini uyandırırken, notifyAll() tüm bekleyen evreleri uyandırır.

notify() çağrılarak hangi thread'in uyanacağı nasıl belirlenir?

Birden fazla thread bekliyorsa notify() çağrılarak hangi threadlerin uyandırılacağı belirtilmez. Bu nedenle kod, herhangi bir somut JVM uygulamasına dayanmamalıdır.

Rastgele İçerik

© tüm hakları saklıdır
made with by templateszoo