Masalah yang diselesaikan oleh multithreading di Jawa
Pada asasnya, multithreading Java dicipta untuk menyelesaikan dua masalah utama:-
Lakukan berbilang tindakan pada masa yang sama.
Dalam contoh di atas, benang yang berbeza (iaitu ahli keluarga) melakukan beberapa tindakan secara selari: mencuci pinggan mangkuk, pergi ke kedai, melipat barang.
Contoh yang lebih "pengaturcara" boleh diberikan. Bayangkan anda mempunyai program dengan antara muka pengguna. Apabila butang Teruskan diklik, beberapa pengiraan harus berlaku dalam program dan pengguna harus melihat skrin antara muka berikut. Jika tindakan ini dijalankan secara berurutan, selepas mengklik butang "Teruskan", program hanya akan membekukan. Pengguna akan melihat skrin yang sama dengan butang "Teruskan" sehingga semua pengiraan dalaman selesai dan program mencapai bahagian di mana antara muka akan mula dilukis.
Baiklah, mari tunggu beberapa minit!
Kami juga boleh membuat semula program kami, atau, seperti yang dikatakan pengaturcara, "sejajarkan." Biarkan pengiraan yang diperlukan dilakukan dalam satu utas, dan pemaparan antara muka dalam yang lain. Kebanyakan komputer mempunyai sumber yang mencukupi untuk ini. Dalam kes ini, program ini tidak akan menjadi "bodoh", dan pengguna akan bergerak dengan tenang antara skrin antara muka tanpa perlu risau tentang apa yang berlaku di dalamnya. Ia tidak mengganggu :)
-
Mempercepatkan pengiraan.
Segala-galanya lebih mudah di sini. Jika pemproses kami mempunyai beberapa teras, dan kebanyakan pemproses kini berbilang teras, senarai tugas kami boleh diselesaikan secara selari dengan beberapa teras. Jelas sekali, jika kita perlu menyelesaikan 1000 masalah dan setiap daripada mereka diselesaikan dalam satu saat, satu teras akan mengatasi senarai dalam 1000 saat, dua teras dalam 500 saat, tiga dalam lebih daripada 333 saat, dan seterusnya.
Thread
. Iaitu, untuk mencipta dan menjalankan 10 utas, anda memerlukan 10 objek kelas ini. Mari tulis contoh paling mudah:
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
Untuk mencipta dan melancarkan benang, kita perlu mencipta kelas dan mewarisinya daripada java.lang
. Thread
dan mengatasi kaedah di dalamnya run()
. Yang terakhir sangat penting. Ia adalah dalam kaedah yang run()
kita menetapkan logik yang thread kita mesti melaksanakan. Sekarang, jika kita mencipta contoh MyFirstThread
dan menjalankannya, kaedah itu run()
akan mencetak baris dengan namanya ke konsol: kaedah getName()
mencetak nama "sistem" benang, yang ditetapkan secara automatik. Walaupun, sebenarnya, mengapa "jika"? Mari buat dan uji!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Output konsol: Saya Thread! Nama saya Thread-2 Saya Thread! Nama saya Thread-1 Saya Thread! Nama saya Thread-0 Saya Thread! Nama saya Thread-3 Saya Thread! Nama saya Thread-6 Saya Thread! Nama saya Thread-7 Saya Thread! Nama saya Thread-4 Saya Thread! Nama saya Thread-5 Saya Thread! Nama saya Thread-9 Saya Thread! Nama saya Thread-8 Kami mencipta 10 utas (objek) MyFirstThread
yang mewarisi Thread
dan melancarkannya dengan memanggil kaedah objek start()
. Selepas memanggil kaedah , start()
kaedahnya mula berfungsi run()
, dan logik yang ditulis di dalamnya dilaksanakan. Sila ambil perhatian: nama benang tidak teratur. Agak pelik, kenapa mereka tidak dibunuh secara bergilir-gilir: Thread-0
, Thread-1
, Thread-2
dan seterusnya? Ini betul-betul contoh apabila pemikiran standard, "berurutan" tidak akan berfungsi. Hakikatnya ialah dalam kes ini kami hanya mengeluarkan arahan untuk mencipta dan melancarkan 10 utas. Dalam susunan apa mereka harus dilancarkan diputuskan oleh penjadual benang: mekanisme khas di dalam sistem pengendalian. Seberapa tepat ia distrukturkan dan atas prinsip apa ia membuat keputusan adalah topik yang sangat kompleks, dan kami tidak akan menyelaminya sekarang. Perkara utama yang perlu diingat ialah pengaturcara tidak dapat mengawal urutan pelaksanaan benang. Untuk menyedari keseriusan keadaan, cuba jalankan kaedah main()
dari contoh di atas beberapa kali lagi. Output konsol kedua: Saya Thread! Nama saya Thread-0 Saya Thread! Nama saya Thread-4 Saya Thread! Nama saya Thread-3 Saya Thread! Nama saya Thread-2 Saya Thread! Nama saya Thread-1 Saya Thread! Nama saya Thread-5 Saya Thread! Nama saya Thread-6 Saya Thread! Nama saya Thread-8 Saya Thread! Nama saya Thread-9 Saya Thread! Nama saya Thread-7 Output konsol ketiga: Saya Thread! Nama saya Thread-0 Saya Thread! Nama saya Thread-3 Saya Thread! Nama saya Thread-1 Saya Thread! Nama saya Thread-2 Saya Thread! Nama saya Thread-6 Saya Thread! Nama saya Thread-4 Saya Thread! Nama saya Thread-9 Saya Thread! Nama saya Thread-5 Saya Thread! Nama saya Thread-7 Saya Thread! Nama saya Thread-8
Masalah yang ditimbulkan oleh multithreading
Dalam contoh dengan buku, anda melihat bahawa multithreading menyelesaikan masalah yang agak penting, dan penggunaannya mempercepatkan kerja program kami. Dalam banyak kes - banyak kali. Tetapi bukan untuk apa-apa bahawa multithreading dianggap sebagai topik yang kompleks. Lagipun, jika digunakan secara tidak betul, ia menimbulkan masalah dan bukannya menyelesaikannya. Apabila saya menyebut "cipta masalah," saya tidak bermaksud sesuatu yang abstrak. Terdapat dua masalah khusus yang boleh menyebabkan multithreading: kebuntuan dan keadaan perlumbaan. Kebuntuan ialah situasi di mana beberapa utas sedang menunggu sumber diduduki oleh satu sama lain, dan tiada satu pun daripada mereka boleh terus melaksanakan. Kami akan bercakap lebih lanjut mengenainya dalam kuliah akan datang, tetapi buat masa ini contoh ini sudah memadai: Bayangkan bahawa thread-1 berfungsi dengan beberapa Objek-1, dan thread-2 berfungsi dengan Objek-2. Program ini ditulis seperti ini:- Thread-1 akan berhenti berfungsi dengan Objek-1 dan bertukar kepada Objek-2 sebaik sahaja Thread-2 berhenti berfungsi dengan Objek 2 dan bertukar kepada Objek-1.
- Thread-2 akan berhenti berfungsi dengan Objek-2 dan bertukar kepada Objek-1 sebaik sahaja Thread-1 berhenti berfungsi dengan Objek 1 dan bertukar kepada Objek-2.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Выполнен поток " + getName());
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Sekarang bayangkan bahawa program itu bertanggungjawab untuk operasi robot yang menyediakan makanan! Thread-0 mengeluarkan telur dari peti sejuk. Aliran 1 menghidupkan dapur. Stream-2 mengeluarkan kuali dan meletakkannya di atas dapur. Aliran 3 menyalakan api di atas dapur. Aliran 4 tuang minyak ke dalam kuali. Aliran 5 pecahkan telur dan tuangkan ke dalam kuali. Aliran 6 membuang cengkerang ke dalam tong sampah. Stream-7 mengeluarkan telur hancur yang telah siap dari api. Potok-8 meletakkan telur hancur di atas pinggan. Stream 9 basuh pinggan. Lihat hasil program kami: Thread-0 executed Thread-2 thread executed Thread-1 thread executed Thread-4 thread executed Thread-9 thread executed Thread-5 thread executed Thread-8 thread executed Thread-7 thread executed Thread-7 thread executed -3 Thread-6 thread executed. Adakah skrip itu menyeronokkan? :) Dan semuanya kerana operasi program kami bergantung pada susunan di mana utas dilaksanakan. Dengan sedikit pun pelanggaran urutan, dapur kami bertukar menjadi neraka, dan robot yang menjadi gila memusnahkan segala-galanya di sekelilingnya. Ini juga merupakan masalah biasa dalam pengaturcaraan berbilang benang, yang akan anda dengar lebih daripada sekali. Pada akhir kuliah, saya ingin mengesyorkan anda sebuah buku mengenai multithreading.
GO TO FULL VERSION