Multithreading ile çözülen problemler
Multithreading aslında iki önemli hedefe ulaşmak için icat edildi:-
Aynı anda birkaç şey yapın.
Yukarıdaki örnekte, farklı gruplar (aile üyeleri) paralel olarak birkaç eylem gerçekleştirmiştir: bulaşıkları yıkadılar, mağazaya gittiler ve eşyaları paketlediler.
Programlama ile daha yakından ilgili bir örnek sunabiliriz. Kullanıcı arayüzü olan bir programınız olduğunu varsayalım. Programda 'Devam Et' butonuna tıkladığınızda bazı hesaplamalar yapılmalı ve kullanıcı aşağıdaki ekranı görmelidir. Bu eylemler sırayla gerçekleştirilirse, kullanıcı 'Devam Et' düğmesini tıkladıktan sonra program askıda kalırdı. Program tüm dahili hesaplamaları yapana ve kullanıcı arayüzünün yenilendiği kısma gelene kadar kullanıcı 'Devam Et' butonu ekranının olduğu ekranı görecektir.
Pekala, sanırım birkaç dakika bekleyeceğiz!
Veya programımızda yeniden çalışabilir veya programcıların dediği gibi onu "paralelleştirebiliriz". Hesaplamalarımızı bir iş parçacığında yapalım ve diğerinde kullanıcı arayüzünü çizelim. Çoğu bilgisayarın bunu yapmak için yeterli kaynağı vardır. Bu rotayı izlersek, program donmayacak ve kullanıcı içeride ne olduğu konusunda endişelenmeden ekranlar arasında sorunsuz hareket edecektir. Biri diğerine karışmaz :)
-
Hesaplamaları daha hızlı yapın.
Burada her şey çok daha basit. İşlemcimizin birden fazla çekirdeği varsa ve bugün çoğu işlemcide varsa, o zaman birkaç çekirdek görev listemizi paralel olarak işleyebilir. Açıkçası, 1000 görev gerçekleştirmemiz gerekirse ve her biri bir saniye sürerse, bir çekirdek listeyi 1000 saniyede, iki çekirdek 500 saniyede, üç çekirdek 333 saniyeden biraz fazla bir sürede vb.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
Konu oluşturmak ve çalıştırmak için, bir sınıf oluşturmamız, java.lang'ı devralmasını sağlamamız gerekir . Thread sınıfını seçin ve run() yöntemini geçersiz kılın. Bu son şart çok önemlidir. İş parçacığımızın yürütme mantığını run() yönteminde tanımlarız. Şimdi, bir MyFirstThread örneği oluşturup çalıştırırsak , run() yöntemi, adı olan bir satır görüntüler: getName() yöntemi, iş parçacığının otomatik olarak atanan 'sistem' adını görüntüler. Ama neden geçici olarak konuşuyoruz? Bir tane oluşturalım ve öğrenelim!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Konsol çıktısı: Ben Konuyum! Adım Thread-2 Ben Thread! Adım Konu-1 Ben Konuyum! Adım Thread-0 Ben Thread! Adım Thread-3 Ben Thread! Adım Thread-6 Ben Thread! Adım Thread-7 Ben Thread! Adım Thread-4 Ben Thread! Adım Thread-5 Ben Thread! Adım Thread-9 Ben Thread! Benim adım Thread-8 10 adet thread ( Thread'i devralan MyFirstThread nesneleri) oluşturalım ve her nesnede start() yöntemini çağırarak bunları başlatalım . start() yöntemi çağrıldıktan sonra run() yöntemindeki mantık yürütülür. Not: Konu adları sıralı değildir. Sırayla olmamaları garip:, Konu-1 , Konu-2 vb. Olduğu gibi, bu 'sıralı' düşünmenin uymadığı bir zaman örneğidir. Sorun şu ki, yalnızca 10 iş parçacığı oluşturmak ve çalıştırmak için komutlar sağladık. Özel bir işletim sistemi mekanizması olan iş parçacığı zamanlayıcı yürütme sırasına karar verir. Kesin tasarımı ve karar verme stratejisi, şu anda derin bir tartışmaya girmeyeceğimiz konular. Hatırlanması gereken en önemli şey, programcının iş parçacıklarının yürütme sırasını kontrol edemediğidir. Durumun ciddiyetini anlamak için yukarıdaki örnekte bulunan main() yöntemini birkaç kez daha çalıştırmayı deneyin. İkinci çalıştırmada konsol çıktısı: Ben İplik! Adım Thread-0 Ben Thread! Adım Thread-4 Ben Thread! Adım Thread-3 Ben Thread! Adım Thread-2 Ben Thread! Adım Konu-1 Ben Konuyum! Adım Thread-5 Ben Thread! Adım Thread-6 Ben Thread! Adım Thread-8 Ben Thread! Adım Thread-9 Ben Thread! Benim adım Thread-7 Konsolun üçüncü çalıştırma çıktısı: Ben Thread! Adım Thread-0 Ben Thread! Adım Thread-3 Ben Thread! Adım Konu-1 Ben Konuyum! Adım Thread-2 Ben Thread! Adım Thread-6 Ben Thread! Adım Thread-4 Ben Thread! Adım Thread-9 Ben Thread! Adım Thread-5 Ben Thread! Adım Thread-7 Ben Thread! Benim adım Konu-8
Çoklu iş parçacığı tarafından oluşturulan sorunlar
Kitaplarla ilgili örneğimizde, çoklu okumanın çok önemli görevleri çözdüğünü ve programlarımızı daha hızlı hale getirebileceğini gördünüz. Genellikle birçok kez daha hızlı. Ancak multithreading zor bir konu olarak kabul edilir. Nitekim yanlış kullanılırsa çözmek yerine sorun yaratır. "Sorun yaratır" dediğimde, soyut anlamda kastetmiyorum. Çoklu iş parçacığının yaratabileceği iki özel sorun vardır: kilitlenme ve yarış koşulları. Kilitlenme, birden çok iş parçacığının birbiri tarafından tutulan kaynakları beklediği ve hiçbirinin çalışmaya devam edemediği bir durumdur. Sonraki derslerde bunun hakkında daha fazla konuşacağız. Şu örnek şimdilik yeterli olacaktır:
- Thread-1, Object-1 ile etkileşimi durdurur ve Thread-2, Object-2 ile etkileşimi durdurur ve Object-1'e geçer geçmez Object-2'ye geçer.
- Thread-2, Object-2 ile etkileşimi durdurur ve Thread-1, Object-1 ile etkileşimi durdurur ve Object-2'ye geçer geçmez Object-1'e geçer.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Thread executed: " + getName());
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Şimdi, programın yemek pişiren bir robotu çalıştırmaktan sorumlu olduğunu hayal edin! Thread-0, yumurtaları buzdolabından çıkarır. Konu-1 ocağı açar. İplik-2 bir tava alır ve ocağa koyar. İplik-3 sobayı yakar. İplik-4 tavaya yağ döker. İplik-5 yumurtaları kırar ve tavaya döker. Thread-6, yumurta kabuklarını çöp kutusuna atar. İplik-7, pişmiş yumurtaları brülörden çıkarır. İplik-8, pişmiş yumurtaları bir tabağa koyar. Thread-9 bulaşıkları yıkar. Programımızın sonuçlarına bakın: İş parçacığı yürütüldü: İş parçacığı-0 Yürütülen iş parçacığı: İş parçacığı-2 İş parçacığı yürütüldü İş parçacığı-1 Yürütülen iş parçacığı: İş parçacığı-4 Yürütülen iş parçacığı: Yürütülen iş parçacığı: İş parçacığı-9 Yürütülen iş parçacığı: İş parçacığı-5 Yürütülen iş parçacığı: İş parçacığı-8 İş parçacığı yürütüldü: Thread-7 Yürütülen thread: Thread-3 Bu bir komedi rutini mi? :) Ve hepsi, programımızın çalışmasının iş parçacıklarının yürütme sırasına bağlı olması nedeniyle. Gerekli sıralamanın en ufak bir ihlali durumunda mutfağımız cehenneme döner ve çılgın bir robot etrafındaki her şeyi yok eder. Bu, çok iş parçacıklı programlamada da yaygın bir sorundur. Bunu bir kereden fazla duyacaksınız. Bu dersi sonlandırırken, çoklu kullanım hakkında bir kitap önermek istiyorum. 
GO TO FULL VERSION