CodeGym /Blog Java /rawak /Multithreading di Jawa
John Squirrels
Tahap
San Francisco

Multithreading di Jawa

Diterbitkan dalam kumpulan
Hai! Pertama sekali, tahniah: anda telah mencapai topik Multithreading di Jawa! Ini adalah pencapaian yang serius — anda telah melangkah jauh. Tetapi sediakan diri anda: ini adalah salah satu topik yang paling sukar dalam kursus. Dan bukannya kami menggunakan kelas yang kompleks atau banyak kaedah di sini: malah, kami akan menggunakan kurang daripada dua puluh. Ia lebih kepada anda perlu mengubah sedikit cara anda berfikir. Sebelum ini, program anda telah dilaksanakan secara berurutan. Beberapa baris kod datang selepas yang lain, beberapa kaedah datang selepas yang lain, dan semuanya pada dasarnya jelas. Mula-mula, kami mengira sesuatu, kemudian memaparkan hasil pada konsol, dan kemudian program berakhir. Untuk memahami multithreading, lebih baik berfikir dari segi paralelisme. Mari kita mulakan dengan sesuatu yang agak mudah: ) Bayangkan keluarga anda sedang berpindah dari satu rumah ke rumah yang lain. Mengumpul semua buku anda akan menjadi bahagian penting dalam langkah itu. Anda telah mengumpul banyak buku, dan anda perlu memasukkannya ke dalam kotak. Pada masa ini, anda seorang sahaja yang tersedia. Ibu sedang menyediakan makanan, abang sedang mengemas pakaian, dan kakak pergi ke kedai. Sendirian, anda boleh menguruskan entah bagaimana. Lambat laun, anda akan menyiapkan tugasan itu sendiri, tetapi ia akan mengambil banyak masa. Walau bagaimanapun, kakak anda akan pulang dari kedai dalam masa 20 minit, dan dia tidak mempunyai apa-apa lagi untuk dilakukan. Jadi dia boleh menyertai anda. Tugasan tidak berubah: masukkan buku ke dalam kotak. Tetapi ia dilakukan dua kali lebih pantas. kenapa? Kerana kerja itu berlaku selari. Dua 'benang' berbeza (anda dan kakak anda) melakukan tugas yang sama secara serentak. Dan jika tiada apa yang berubah, maka akan ada perbezaan masa yang besar berbanding dengan situasi di mana anda melakukan segala-galanya sendiri. Jika abang menyelesaikan tugasnya tidak lama lagi, dia boleh membantu anda dan perkara akan berjalan dengan lebih cepat.

Masalah diselesaikan dengan multithreading

Multithreading sebenarnya dicipta untuk mencapai dua objektif penting:
  1. Lakukan beberapa perkara pada masa yang sama.

    Dalam contoh di atas, benang yang berbeza (ahli keluarga) melakukan beberapa tindakan secara selari: mereka mencuci pinggan mangkuk, pergi ke kedai dan mengemas barang.

    Kami boleh menawarkan contoh yang lebih rapat dengan pengaturcaraan. Katakan anda mempunyai program dengan antara muka pengguna. Apabila anda mengklik 'Teruskan' dalam program, beberapa pengiraan akan berlaku dan pengguna harus melihat skrin berikut. Jika tindakan ini dilakukan secara berurutan, maka program hanya akan tergantung selepas pengguna mengklik butang 'Teruskan'. Pengguna akan melihat skrin dengan skrin butang 'Teruskan' sehingga program melakukan semua pengiraan dalaman dan mencapai bahagian di mana antara muka pengguna dimuat semula.

    Baiklah, saya rasa kita akan tunggu beberapa minit!

    Multithreading di Jawa: apakah itu, faedahnya dan perangkap biasa - 3

    Atau kita boleh mengolah semula program kita, atau, seperti yang dikatakan pengaturcara, 'sejajarkan' ia. Mari kita lakukan pengiraan kami pada satu utas dan lukis antara muka pengguna pada satu lagi. Kebanyakan komputer mempunyai sumber yang mencukupi untuk melakukan ini. Jika kami mengambil laluan ini, maka program tidak akan membeku dan pengguna akan bergerak dengan lancar antara skrin tanpa perlu risau tentang apa yang berlaku di dalam. Yang satu tidak mengganggu yang lain :)

  2. Lakukan pengiraan dengan lebih cepat.

    Segala-galanya lebih mudah di sini. Jika pemproses kami mempunyai berbilang teras, dan kebanyakan pemproses hari ini melakukannya, maka beberapa teras boleh mengendalikan senarai tugas kami secara selari. Jelas sekali, jika kita perlu melaksanakan 1000 tugasan dan setiap satu mengambil masa satu saat, satu teras boleh menyelesaikan senarai dalam 1000 saat, dua teras dalam 500 saat, tiga dalam masa lebih sedikit daripada 333 saat, dsb.

Tetapi seperti yang anda telah baca dalam pelajaran ini, sistem hari ini sangat pintar, dan pada satu teras pengkomputeran pun dapat mencapai keselarian, atau lebih tepatnya pseudo-paralelisme, di mana tugas dilakukan secara bergilir-gilir. Mari kita alihkan generaliti kepada khusus dan kenali kelas yang paling penting dalam pustaka multithreading Java — java.lang.Thread. Tegasnya, benang Java diwakili oleh contoh kelas Benang . Ini bermakna untuk mencipta dan menjalankan 10 utas, anda memerlukan 10 kejadian 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 menjalankan benang, kita perlu mencipta kelas, menjadikannya mewarisi java.lang . Kelas benang , dan ganti kaedah run() nya . Keperluan terakhir itu sangat penting. Dalam kaedah run() kami mentakrifkan logik untuk thread kami untuk dilaksanakan. Sekarang, jika kita mencipta dan menjalankan contoh MyFirstThread , kaedah run() akan memaparkan baris dengan nama: kaedah getName() memaparkan nama 'sistem' benang, yang ditetapkan secara automatik. Tetapi mengapa kita bercakap secara tentatif? Mari buat satu dan ketahui!

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 Mari buat 10 thread ( objek MyFirstThread , yang mewarisi Thread ) dan mulakannya dengan memanggil kaedah start() pada setiap objek. Selepas memanggil kaedah start() , logik dalam kaedah run() dilaksanakan. Nota: nama benang tidak teratur. Adalah pelik bahawa mereka tidak berurutan:, Thread-1 , Thread-2 dan seterusnya? Seperti yang berlaku, ini adalah contoh masa apabila pemikiran 'berurutan' tidak sesuai. Isunya ialah kami hanya menyediakan arahan untuk mencipta dan menjalankan 10 utas. Penjadual benang, mekanisme sistem pengendalian khas, memutuskan perintah pelaksanaannya. Reka bentuk yang tepat dan strategi membuat keputusan adalah topik untuk perbincangan mendalam yang tidak akan kami teliti sekarang. Perkara utama yang perlu diingat ialah pengaturcara tidak dapat mengawal susunan pelaksanaan benang. Untuk memahami keseriusan keadaan, cuba jalankan kaedah main() dalam contoh di atas beberapa kali lagi. Output konsol pada larian 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 ialah keluaran Konsol Thread-7 daripada larian 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 dicipta oleh multithreading

Dalam contoh kami dengan buku, anda melihat bahawa multithreading menyelesaikan tugas yang sangat penting dan boleh menjadikan program kami lebih pantas. Selalunya berkali ganda lebih pantas. Tetapi multithreading dianggap sebagai topik yang sukar. Sesungguhnya, jika digunakan secara tidak wajar, ia menimbulkan masalah dan bukannya menyelesaikannya. Apabila saya katakan 'mencipta masalah', saya tidak bermaksud dalam erti kata yang abstrak. Terdapat dua masalah khusus yang boleh dibuat oleh multithreading: kebuntuan dan keadaan perlumbaan. Kebuntuan ialah situasi di mana beberapa utas sedang menunggu sumber yang dipegang oleh satu sama lain, dan tiada satu pun daripada mereka boleh terus berjalan. Kami akan bercakap lebih lanjut mengenainya dalam pelajaran seterusnya. Contoh berikut akan mencukupi buat masa ini: Multithreading di Jawa: apakah itu, faedahnya dan perangkap biasa - 4Bayangkan bahawa Thread-1 berinteraksi dengan beberapa Objek-1, dan Thread-2 berinteraksi dengan Objek-2. Tambahan pula, program ini ditulis supaya:
  1. Thread-1 berhenti berinteraksi dengan Objek-1 dan bertukar kepada Objek-2 sebaik sahaja Thread-2 berhenti berinteraksi dengan Objek-2 dan bertukar kepada Objek-1.
  2. Thread-2 berhenti berinteraksi dengan Objek-2 dan bertukar kepada Objek-1 sebaik sahaja Thread-1 berhenti berinteraksi dengan Objek-1 dan bertukar kepada Objek-2.
Walaupun tanpa pemahaman mendalam tentang multithreading, anda boleh melihat dengan mudah bahawa tiada apa yang akan berlaku. Benang tidak akan bertukar tempat dan akan menunggu antara satu sama lain selama-lamanya. Kesilapan nampak jelas, tetapi sebenarnya tidak. Anda boleh melakukan ini dengan mudah dalam program. Kami akan mempertimbangkan contoh kod yang menyebabkan kebuntuan dalam pelajaran seterusnya. By the way, Quora mempunyai contoh kehidupan sebenar yang hebat yang menerangkan kebuntuan ituialah. 'Di sesetengah negeri di India, mereka tidak akan menjual tanah pertanian kepada anda melainkan anda seorang petani berdaftar. Walau bagaimanapun, mereka tidak akan mendaftarkan anda sebagai petani jika anda tidak memiliki tanah pertanian'. Hebat! Apa yang boleh kita katakan?! :) Sekarang mari kita bercakap tentang keadaan perlumbaan. Keadaan perlumbaan ialah ralat reka bentuk dalam sistem atau aplikasi berbilang benang, di mana pengendalian sistem atau aplikasi bergantung pada susunan bahagian kod itu dilaksanakan. Ingat, contoh kami di mana kami memulakan urutan:

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();
       }
   }
}
Sekarang bayangkan bahawa program ini bertanggungjawab untuk menjalankan robot yang memasak makanan! Thread-0 mengeluarkan telur dari peti sejuk. Benang-1 menghidupkan dapur. Benang-2 mendapat kuali dan meletakkannya di atas dapur. Benang-3 menyalakan dapur. Benang-4 menuang minyak ke dalam kuali. Benang-5 memecahkan telur dan menuangkannya ke dalam kuali. Benang-6 membuang kulit telur ke dalam tong sampah. Benang-7 mengeluarkan telur masak dari penunu. Thread-8 meletakkan telur yang telah dimasak di atas pinggan. Benang-9 membasuh pinggan. Lihat hasil program kami: Thread dilaksanakan: Thread-0 Thread dilaksanakan: Thread-2 Thread dilaksanakan Thread-1 Thread dilaksanakan: Thread-4 Thread dilaksanakan: Thread-9 Thread dilaksanakan: Thread-5 Thread dilaksanakan: Thread-8 Thread dilaksanakan: Thread-7 Thread dilaksanakan: Thread-3 Adakah ini rutin komedi? :) Dan semuanya kerana kerja program kami bergantung pada susunan pelaksanaan utas. Memandangkan sedikit pun pelanggaran urutan yang diperlukan, dapur kami bertukar menjadi neraka, dan robot gila memusnahkan segala-galanya di sekelilingnya. Ini juga merupakan masalah biasa dalam pengaturcaraan berbilang benang. Anda akan mendengarnya lebih daripada sekali. Sebagai mengakhiri pelajaran ini, saya ingin mengesyorkan buku tentang multithreading. Multithreading di Jawa: apakah itu, faedahnya dan perangkap biasa - 6'Java Concurrency in Practice' telah ditulis pada tahun 2006, tetapi tidak kehilangan kaitannya. Ia didedikasikan untuk pengaturcaraan Java berbilang benang — daripada asas kepada kesilapan dan antipattern yang paling biasa. Jika anda suatu hari nanti memutuskan untuk menjadi guru multithreading, buku ini mesti dibaca. Jumpa anda dalam pelajaran seterusnya! :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION