pengenalan
Aliran adalah perkara yang menarik. Dalam ulasan sebelumnya, kami melihat beberapa alat yang tersedia untuk melaksanakan multithreading. Mari lihat apa lagi perkara menarik yang boleh kita lakukan. Pada ketika ini kita tahu banyak. Contohnya, daripada "
Anda Tidak Boleh Merosakkan Java dengan Benang: Bahagian I - Benang, " kita tahu bahawa benang ialah Benang. Kami tahu bahawa benang sedang melaksanakan beberapa tugas. Jika kita mahu tugas kita dapat dijalankan (
run
), maka kita mesti menentukan benang untuk menjadi tertentu
Runnable
.
Untuk diingati, kita boleh menggunakan
Tutorialspoint Java Online Compiler :
public static void main(String []args){
Runnable task = () -> {
Thread thread = Thread.currentThread();
System.out.println("Hello from " + thread.getName());
};
Thread thread = new Thread(task);
thread.start();
}
Kami juga tahu bahawa kami mempunyai konsep seperti kunci. Kami membaca tentangnya dalam "
Anda Tidak Boleh Merosakkan Java dengan Benang: Bahagian II - Penyegerakan ." Benang boleh menduduki kunci dan kemudian benang lain yang cuba mengisi kunci akan terpaksa menunggu kunci menjadi bebas:
import java.util.concurrent.locks.*;
public class HelloWorld{
public static void main(String []args){
Lock lock = new ReentrantLock();
Runnable task = () -> {
lock.lock();
Thread thread = Thread.currentThread();
System.out.println("Hello from " + thread.getName());
lock.unlock();
};
Thread thread = new Thread(task);
thread.start();
}
}
Saya rasa sudah tiba masanya untuk bercakap tentang perkara lain yang boleh kita lakukan yang menarik.
Semaphore
Cara paling mudah untuk mengawal bilangan utas yang boleh berfungsi secara serentak ialah semafor. Seperti di landasan kereta api. Lampu hijau menyala - anda boleh. Lampu merah menyala - kami sedang menunggu. Apa yang kita harapkan daripada semafor? kebenaran. Kebenaran dalam bahasa Inggeris - permit. Untuk mendapatkan kebenaran, anda perlu mendapatkannya, yang dalam bahasa Inggeris akan diperoleh. Dan apabila kebenaran itu tidak diperlukan lagi, kita mesti memberikannya, iaitu melepaskannya atau menyingkirkannya, yang dalam bahasa Inggeris akan dilepaskan. Mari lihat bagaimana ia berfungsi. Kami perlu mengimport kelas tersebut
java.util.concurrent.Semaphore
. Contoh:
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(0);
Runnable task = () -> {
try {
semaphore.acquire();
System.out.println("Finished");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(task).start();
Thread.sleep(5000);
semaphore.release(1);
}
Seperti yang kita dapat lihat, setelah menghafal perkataan Inggeris, kita memahami bagaimana semaphore berfungsi. Menariknya, syarat utama ialah "akaun" semaphore mesti mempunyai bilangan permit yang positif. Oleh itu, anda boleh memulakannya dengan tolak. Dan anda boleh meminta (memperoleh) lebih daripada 1.
CountDownLatch
Mekanisme seterusnya ialah
CountDownLatch
. Countdown dalam bahasa Inggeris ialah undur, dan Latch ialah bolt atau selak. Iaitu, jika kita menterjemahkannya, maka ini adalah selak dengan kira detik. Di sini kita memerlukan import kelas yang sesuai
java.util.concurrent.CountDownLatch
. Ia seperti perlumbaan atau perlumbaan di mana semua orang berkumpul di garisan permulaan dan apabila semua orang bersedia, kebenaran diberikan dan semua orang bermula pada masa yang sama. Contoh:
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
Runnable task = () -> {
try {
countDownLatch.countDown();
System.out.println("Countdown: " + countDownLatch.getCount());
countDownLatch.await();
System.out.println("Finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
tunggu dalam bahasa Inggeris - untuk mengharapkan. Maksudnya, kita bercakap dahulu
countDown
. Seperti yang dikatakan oleh Penterjemah Google, mengira detik ialah "tindakan mengira angka dalam susunan terbalik kepada sifar," iaitu, melakukan tindakan kira detik, yang tujuannya adalah untuk mengira hingga sifar. Dan kemudian kita katakan
await
- iaitu, tunggu sehingga nilai pembilang menjadi sifar. Adalah menarik bahawa kaunter sebegitu boleh guna. Seperti yang dikatakan dalam JavaDoc - "Apabila benang mesti berulang kali mengira mundur dengan cara ini, sebaliknya gunakan CyclicBarrier", iaitu, jika anda memerlukan pengiraan boleh guna semula, anda perlu menggunakan pilihan lain, yang dipanggil
CyclicBarrier
.
Penghalang Kitaran
Seperti namanya,
CyclicBarrier
ia adalah penghalang kitaran. Kami perlu mengimport kelas tersebut
java.util.concurrent.CyclicBarrier
. Mari lihat contoh:
public static void main(String[] args) throws InterruptedException {
Runnable action = () -> System.out.println("На старт!");
CyclicBarrier berrier = new CyclicBarrier(3, action);
Runnable task = () -> {
try {
berrier.await();
System.out.println("Finished");
} catch (BrokenBarrierException | InterruptedException e) {
e.printStackTrace();
}
};
System.out.println("Limit: " + berrier.getParties());
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
Seperti yang anda lihat, utas sedang melaksanakan
await
, iaitu menunggu. Dalam kes ini, nilai penghalang berkurangan. Penghalang dianggap pecah (
berrier.isBroken()
) apabila kira detik mencapai sifar. Untuk menetapkan semula halangan, anda perlu memanggil
berrier.reset()
, yang tiada dalam
CountDownLatch
.
Penukar
Ubat seterusnya ialah
Exchanger
. Pertukaran daripada bahasa Inggeris diterjemahkan sebagai pertukaran atau pertukaran. A
Exchanger
ialah penukar, iaitu sesuatu yang melaluinya mereka bertukar. Mari lihat contoh mudah:
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
Runnable task = () -> {
try {
Thread thread = Thread.currentThread();
String withThreadName = exchanger.exchange(thread.getName());
System.out.println(thread.getName() + " обменялся с " + withThreadName);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(task).start();
new Thread(task).start();
}
Di sini kami melancarkan dua utas. Setiap daripada mereka melaksanakan kaedah pertukaran dan menunggu thread lain untuk turut melaksanakan kaedah pertukaran. Oleh itu, benang akan bertukar-tukar hujah yang diluluskan sesama mereka. Perkara yang menarik. Adakah dia tidak mengingatkan anda tentang apa-apa? Dan dia mengingatkan
SynchronousQueue
, yang terletak di tengah-tengah
cachedThreadPool
'a. Untuk kejelasan, berikut adalah contoh:
public static void main(String[] args) throws InterruptedException {
SynchronousQueue<String> queue = new SynchronousQueue<>();
Runnable task = () -> {
try {
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(task).start();
queue.put("Message");
}
Contoh menunjukkan bahawa dengan melancarkan utas baharu, utas ini akan masuk ke mod menunggu, kerana baris gilir akan kosong. Dan kemudian
main
benang akan beratur teks "Mesej". Pada masa yang sama, ia akan berhenti untuk masa yang diperlukan sehingga ia menerima elemen teks ini daripada baris gilir. Mengenai topik ini anda juga boleh membaca "
SynchronousQueue Vs Exchanger ".
Fasa
Dan akhirnya, perkara yang paling manis -
Phaser
. Kami perlu mengimport kelas tersebut
java.util.concurrent.Phaser
. Mari lihat contoh mudah:
public static void main(String[] args) throws InterruptedException {
Phaser phaser = new Phaser();
phaser.register();
System.out.println("Phasecount is " + phaser.getPhase());
testPhaser(phaser);
testPhaser(phaser);
testPhaser(phaser);
Thread.sleep(3000);
phaser.arriveAndDeregister();
System.out.println("Phasecount is " + phaser.getPhase());
}
private static void testPhaser(final Phaser phaser) {
phaser.register();
new Thread(() -> {
String name = Thread.currentThread().getName();
System.out.println(name + " arrived");
phaser.arriveAndAwaitAdvance();
System.out.println(name + " after passing barrier");
}).start();
}
Contoh menunjukkan bahawa halangan, apabila menggunakan
Phaser
'a, dipecahkan apabila bilangan pendaftaran bertepatan dengan bilangan ketibaan di penghalang. Anda boleh mengetahui lebih lanjut
Phaser
dalam artikel dari hab "
Penyegerak Fasa Baharu ".
Keputusan
Seperti yang anda lihat daripada contoh, terdapat pelbagai cara untuk menyegerakkan benang. Tadi saya cuba mengingati sesuatu tentang multithreading, saya harap bahagian sebelum ini berguna. Mereka mengatakan bahawa laluan ke multithreading bermula dengan buku "Java Concurrency in Practice". Walaupun ia dikeluarkan pada tahun 2006, orang ramai menjawab bahawa buku itu agak asas dan masih mempunyai kelebihan. Sebagai contoh, anda boleh membaca perbincangan di sini: "
Adakah Java Concurrency In Practice masih sah? ". Ia juga berguna untuk membaca pautan daripada perbincangan. Sebagai contoh, terdapat pautan ke buku "
The Well-Grounded Java Developer ", di mana ia patut diberi perhatian kepada "
Bab 4. Modern concurrency ". Terdapat satu lagi ulasan keseluruhan mengenai topik yang sama: "
Adakah Java cocurrency in pracitce masih relevan dalam era java 8 ". Ia juga mempunyai petua tentang perkara lain yang perlu anda baca untuk benar-benar memahami topik tersebut. Selepas itu, anda boleh melihat dengan lebih dekat buku yang begitu menarik seperti "
Ujian Amalan Pengaturcara OCA OCP JavaSE 8 ". Kami berminat dengan bahagian kedua iaitu OCP. Dan terdapat ujian dalam "∫". Buku ini mengandungi kedua-dua soalan dan jawapan dengan penjelasan. Sebagai contoh:
Ramai mungkin mula mengatakan bahawa ini hanyalah satu lagi hafalan kaedah. Di satu pihak, ya. Sebaliknya, soalan ini boleh dijawab dengan mengingati bahawa
ExecutorService
ini adalah sejenis "naik taraf"
Executor
. Dan
Executor
ia bertujuan semata-mata untuk menyembunyikan kaedah mencipta benang, tetapi bukan cara utama melaksanakannya, iaitu, berjalan dalam benang baru
Runnable
. Oleh itu,
execute(Callable)
tidak, kerana mereka hanya menambah kaedah
ExecutorService
yang boleh mengembalikan . Seperti yang anda lihat, kami boleh menghafal senarai kaedah, tetapi lebih mudah untuk meneka jika kami mengetahui sifat kelas itu sendiri. Nah, beberapa bahan tambahan mengenai topik:
Executor
submit
Future
#Viacheslav
GO TO FULL VERSION