MERHABA! Bugün multithreading hakkında konuşmaya devam edeceğiz. Şimdi Thread sınıfını ve birkaç yönteminin ne işe yaradığını inceleyelim. Daha önce sınıf yöntemlerini incelerken, genellikle şunu yazardık: <yöntem adı> -> <yöntem ne yapar>. ' nin yöntemleriyle bu iş olmaz
Thread
:) Birkaç örnek vermeden anlayamayacağınız daha karmaşık bir mantıkları var.
Thread.start() yöntemi
Kendimizi tekrar ederek başlayalım.Thread
Muhtemelen hatırladığınız gibi, sınıfınızın sınıfı miras almasını sağlayarak ve yöntemi geçersiz kılarak bir iş parçacığı oluşturabilirsiniz run()
. Ama tabii ki kendi kendine başlamayacak. Bunu yapmak için nesnemizin start()
yöntemini çağırıyoruz. Bir önceki dersteki örneği hatırlayalım:
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();
}
}
}
Not:start()
Bir iş parçacığı başlatmak için, yöntem yerineözel yöntemi çağırmalısınızrun()
! Bu, özellikle multithreading çalışmaya ilk başladığınızda, yapılması kolay bir hatadır. Örneğimizde, yöntemirun()
yerine 10 kezstart()
, şunu elde edersiniz:
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.run();
}
}
}
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ığı-1 Yürütülen iş parçacığı: İş parçacığı-2 Yürütülen iş parçacığı: İş parçacığı-3 Yürütülen iş parçacığı: İş parçacığı-4 Yürütülen iş parçacığı: İş parçacığı-5 Yürütülen iş parçacığı: İş parçacığı-6 Yürütülen iş parçacığı: İş parçacığı-7 Yürütülen iş parçacığı: İş parçacığı-8 Yürütülen iş parçacığı: İş parçacığı-9 Çıktı sırasına bakın: Her şey mükemmel bir sırayla oluyor. Tuhaf, değil mi? Buna alışkın değiliz, çünkü iş parçacıklarının başlatılma ve yürütülme sırasının işletim sistemimizin içindeki üstün bir akıl tarafından belirlendiğini zaten biliyoruz: iş parçacığı planlayıcı. Belki de sadece şanslıydık? Tabii bu şans meselesi değil. Programı birkaç kez daha çalıştırarak bunu doğrulayabilirsiniz. Sorun şu ki, çağrırun()
yöntemin doğrudan çoklu okuma ile ilgisi yoktur. Bu durumda program, yöntemi yürüten aynı iş parçacığı olan ana iş parçacığında yürütülecektir main()
. Konsolda art arda 10 satır yazdırır ve bu kadar. 10 konu başlatılmamış. Bu nedenle, gelecekte bunu hatırlayın ve kendinizi sürekli kontrol edin. run()
Yöntemin çağrılmasını istiyorsanız , arayın start()
. Daha ileri gidelim.
Thread.sleep() yöntemi
Geçerli iş parçacığının yürütülmesini bir süre askıya almak için yöntemi kullanırızsleep()
. Yöntem sleep()
, iş parçacığını uyku moduna geçirmek için gereken süreyi belirten bir argüman olarak birkaç milisaniye alır.
public class Main {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(3000);
System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");
}
}
Konsol çıktısı: - Ne kadar uyudum? - 3 saniye Not: yöntem sleep()
statiktir: geçerli iş parçacığını uyutur. Yani, şu anda idam edilen. İşte başka bir önemli nokta: Uyuyan bir iş parçacığı kesilebilir. Bu durumda, program bir InterruptedException
. Aşağıda bir örnek ele alacağız. Bu arada, iş parçacığı uyandıktan sonra ne olur? Kaldığı yerden devam edecek mi? Hayır. Bir iş parçacığı uyandıktan sonra, yani argüman olarak geçen süre geçtikten sonra, çalıştırılabilirThread.sleep()
hale geçer.durum. Ancak bu, iş parçacığı zamanlayıcının onu çalıştıracağı anlamına gelmez. Uyumayan başka bir ipliği tercih edebilir ve yeni uyanan ipliğimizin biraz sonra işine devam etmesine izin verebilir. Şunu unutmayın: uyanmak, çalışmaya hemen devam etmek anlamına gelmez!
Thread.join() yöntemi
Yöntemjoin()
, başka bir iş parçacığı bitene kadar geçerli iş parçacığının yürütülmesini askıya alır. 2 iş parçacığımız varsa t1
ve t2
, ve yazarız
t1.join()
işini bitirene t2
kadar başlamaz . t1
Yöntem join()
, iş parçacıklarının yürütme sırasını garanti etmek için kullanılabilir. join()
Aşağıdaki örnekte yöntemin nasıl çalıştığını inceleyelim :
public class ThreadExample extends Thread {
@Override
public void run() {
System.out.println("Thread started: " + getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + getName() + " is finished.");
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadExample t1 = new ThreadExample();
ThreadExample t2 = new ThreadExample();
t1.start();
/* The second thread (t2) will start running only after the first thread (t1)
is finished (or an exception is thrown) */
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
// The main thread will continue running only after t1 and t2 have finished
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All threads have finished. The program is finished.");
}
}
Basit bir sınıf oluşturduk ThreadExample
. Görevi, iş parçacığının başladığına dair bir mesaj görüntülemek, 5 saniye uykuya dalmak ve sonunda işin tamamlandığını bildirmektir. Kekin parçası. Ana mantık sınıftadır Main
. Yorumlara bakın: Yöntemi, join()
dizilerin yürütme sırasını başarılı bir şekilde yönetmek için kullanıyoruz. Bu konuya nasıl başladığımızı hatırlarsanız, yürütme sırası iş parçacığı zamanlayıcısı tarafından gerçekleştirilir. Konuları kendi takdirine bağlı olarak çalıştırır: her seferinde farklı bir şekilde. Burada, t1
iş parçacığının önce başlatılacağını ve önce yürütüleceğini, ardındant2
iş parçacığı ve ancak bundan sonra programın ana iş parçacığı devam edecek. Hareketli. Gerçek programlarda, genellikle bir iş parçacığının yürütülmesini kesmeniz gereken durumlar bulacaksınız. Örneğin, iş parçacığımız çalışıyor, ancak belirli bir olay veya koşulu bekliyor. Bu meydana gelirse, iş parçacığı durur. Bir çeşit yöntem olsaydı, muhtemelen mantıklı olurdu stop()
. Ama o kadar basit değil. Bir zamanlar Java'nın aslında bir Thread.stop()
yöntemi vardı ve bir iş parçacığının kesilmesine izin veriyordu. Ancak daha sonra Java kitaplığından kaldırıldı. Bunu Oracle belgelerinde bulabilir ve kullanımdan kaldırılmış olarak işaretlendiğini görebilirsiniz.. Neden? Çünkü başka bir şey yapmadan sadece ipliği durdurdu. Örneğin, iş parçacığı verilerle çalışıyor ve bir şeyi değiştiriyor olabilir. Sonra, işinin ortasında, stop()
yöntem tarafından aniden ve belirsiz bir şekilde kesildi. Düzgün bir kapatma olmadan, kaynakların serbest bırakılması olmadan, hatta hata işleme olmadan - bunların hiçbiri yoktu. Biraz abartmak gerekirse, stop()
yöntem basitçe yoluna çıkan her şeyi yok etti. Bilgisayarı kapatmak için güç kablosunu prizden çekmek gibiydi. Evet, istediğiniz sonucu elde edebilirsiniz. Ama herkes biliyor ki birkaç hafta sonra bilgisayar ona bu şekilde davrandığınız için size teşekkür etmeyecek. Bu nedenle Java'da iş parçacıklarını kesme mantığı değişti ve artık özel bir interrupt()
yöntem kullanıyor.
Thread.interrupt() yöntemi
interrupt()
Yöntem bir iş parçacığında çağrılırsa ne olur ? 2 olasılık var:
join
Nesne, örneğin or yöntemleri nedeniyle bekleme durumundaysasleep
, bekleme kesilir ve program birInterruptedException
.- İş parçacığı çalışır durumdaysa,
interrupted
nesne üzerinde boole bayrağı ayarlanır.
Thread
sınıfın yöntemi vardır boolean isInterrupted()
. Temel kurstaki bir derste olan saat örneğine geri dönelim. Kolaylık sağlamak için biraz basitleştirdik:
public class Clock extends Thread {
public static void main(String[] args) throws InterruptedException {
Clock clock = new Clock();
clock.start();
Thread.sleep(10000);
clock.interrupt();
}
public void run() {
Thread current = Thread.currentThread();
while (!current.isInterrupted())
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("The thread was interrupted");
break;
}
System.out.println("Tick");
}
}
}
Bu durumda saat çalışmaya başlar ve her saniye işlemeye başlar. 10. saniyede saatin akışını kesiyoruz. Bildiğiniz gibi, kesmeye çalıştığımız iş parçacığı bekleme durumlarından birindeyse, sonuç bir InterruptedException
. Bu kontrol edilmiş bir istisnadır, bu yüzden kolayca yakalayabilir ve programı bitirmek için mantığımızı çalıştırabiliriz. Ve biz de öyle yaptık. İşte sonucumuz: Tik Tick Tick Tick Tick Tick Tick Tick Tick Tik Tik Tick Tick İş parçacığı kesintiye uğradı Bu, Thread
sınıfın en önemli yöntemlerine girişimizi sonlandırıyor. İyi şanlar!
GO TO FULL VERSION