Perkenalan
Streaming adalah hal yang menarik. Dalam ulasan sebelumnya, kita melihat beberapa alat yang tersedia untuk mengimplementasikan multithreading. Mari kita lihat hal menarik apa lagi yang bisa kita lakukan. Saat ini kita tahu banyak. Misalnya, dari “
Anda Tidak Dapat Memanjakan Java dengan Thread: Bagian I - Threads, ” kita tahu bahwa thread adalah Thread. Kita tahu bahwa thread sedang melakukan beberapa tugas. Jika kita ingin tugas kita dapat dijalankan (
run
), maka kita harus menentukan threadnya sebagai
Runnable
.
Yang perlu diingat, kita bisa 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();
}
Kita juga tahu bahwa kita mempunyai konsep seperti kunci. Kita membacanya di “
Anda Tidak Dapat Memanjakan Java dengan Thread: Bagian II - Sinkronisasi .” Sebuah thread dapat menempati sebuah kunci dan kemudian thread lain yang mencoba menempati kunci tersebut akan terpaksa menunggu hingga kunci tersebut 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 pikir ini saatnya membicarakan hal menarik lainnya yang bisa kita lakukan.
Semafor
Cara paling sederhana untuk mengontrol berapa banyak thread yang dapat bekerja secara bersamaan adalah semaphore. Seperti di rel kereta api. Lampu hijau menyala - Anda bisa. Lampu merah menyala - kami menunggu. Apa yang kita harapkan dari semaphore? Izin. Izin dalam bahasa Inggris - izin. Untuk mendapatkan izin, Anda perlu mendapatkannya, yang dalam bahasa Inggris akan diperoleh. Dan bila izin itu sudah tidak diperlukan lagi, maka kita harus memberikannya, yaitu melepaskan atau membuangnya, yang dalam bahasa Inggris disebut pelepasan. Mari kita lihat cara kerjanya. Kita perlu mengimpor kelas
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 bisa kita lihat, setelah menghafal kata-kata bahasa Inggris, kita memahami cara kerja semaphore. Menariknya, syarat utamanya adalah “akun” semaphore tersebut harus memiliki jumlah izin yang positif. Oleh karena itu, Anda dapat memulainya dengan nilai minus. Dan Anda dapat meminta (memperoleh) lebih dari 1.
Hitung MundurLatch
Mekanisme selanjutnya adalah
CountDownLatch
. CountDown dalam bahasa Inggris adalah countdown, dan Latch adalah baut atau latch. Artinya, jika kita terjemahkan, maka ini adalah kait dengan hitungan mundur. Di sini kita memerlukan impor kelas yang sesuai
java.util.concurrent.CountDownLatch
. Ibarat perlombaan atau perlombaan dimana semua orang berkumpul di garis start dan ketika semua orang sudah siap, izin diberikan dan semua orang memulai pada waktu 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();
}
}
menunggu dalam bahasa Inggris - mengharapkan. Artinya, kita bicara dulu
countDown
. Seperti yang dikatakan Google Translator, hitung mundur adalah “tindakan menghitung angka dalam urutan terbalik ke nol”, yaitu melakukan tindakan hitung mundur, yang tujuannya adalah menghitung sampai nol. Dan kemudian kita katakan
await
- yaitu, tunggu sampai nilai penghitungnya menjadi nol. Sangat menarik bahwa penghitung seperti itu dapat dibuang. Seperti yang dikatakan di JavaDoc - "Ketika utas harus berulang kali menghitung mundur dengan cara ini, gunakan CyclicBarrier sebagai gantinya", yaitu, jika Anda memerlukan penghitungan yang dapat digunakan kembali, Anda perlu menggunakan opsi lain, yang disebut
CyclicBarrier
.
Penghalang Siklik
Seperti namanya,
CyclicBarrier
ini adalah penghalang siklus. Kita perlu mengimpor kelas
java.util.concurrent.CyclicBarrier
. Mari kita lihat sebuah 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, thread sedang dieksekusi
await
, yaitu menunggu. Dalam hal ini, nilai penghalangnya berkurang. Penghalang dianggap rusak (
berrier.isBroken()
) ketika hitungan mundur mencapai nol. Untuk mengatur ulang penghalang, Anda perlu menelepon
berrier.reset()
, yang tidak ada di
CountDownLatch
.
Penukar
Obat selanjutnya adalah
Exchanger
. Exchange dari bahasa Inggris diterjemahkan sebagai exchange atau pertukaran. A
Exchanger
adalah penukar, yaitu sesuatu yang melaluinya mereka bertukar. Mari kita lihat contoh sederhana:
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 meluncurkan dua utas. Masing-masing mengeksekusi metode pertukaran dan menunggu thread lain juga menjalankan metode pertukaran. Dengan demikian, thread akan bertukar argumen yang disampaikan satu sama lain. Hal yang menarik. Apa dia tidak mengingatkanmu pada sesuatu? Dan beliau mengingatkan
SynchronousQueue
, yang terletak pada inti
cachedThreadPool
'a. Agar lebih jelas, berikut contohnya:
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 bahwa dengan meluncurkan thread baru, thread ini akan masuk ke mode tunggu, karena antrian akan kosong. Dan kemudian
main
thread akan memasukkan teks “Pesan” ke dalam antrian. Pada saat yang sama, ini akan berhenti selama waktu yang diperlukan hingga elemen teks ini diterima dari antrian. Pada topik ini Anda juga dapat membaca "
SynchronousQueue Vs Exchanger ".
Faser
Dan akhirnya, hal yang paling manis -
Phaser
. Kita perlu mengimpor kelas
java.util.concurrent.Phaser
. Mari kita lihat contoh sederhana:
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 bahwa penghalang ketika menggunakan
Phaser
'a akan rusak ketika jumlah pendaftaran bertepatan dengan jumlah kedatangan di penghalang. Anda dapat mengetahui lebih lanjut
Phaser
di artikel dari hub "
Sinkronisasi Phaser Baru ".
Hasil
Seperti yang Anda lihat dari contoh, ada berbagai cara untuk menyinkronkan thread. Tadi saya mencoba mengingat sesuatu tentang multithreading, semoga bagian sebelumnya bermanfaat. Mereka mengatakan bahwa jalan menuju multithreading dimulai dengan buku "Java Concurrency in Practice". Meski terbit pada tahun 2006, masyarakat menanggapi bahwa buku tersebut cukup mendasar dan tetap menarik. Misalnya, Anda dapat membaca diskusi di sini: "
Apakah Java Concurrency In Practice masih valid? ". Membaca tautan dari diskusi juga bermanfaat. Misalnya, ada link ke buku "
Pengembang Java yang Beralas Baik ", yang patut diperhatikan"
Bab 4. Konkurensi modern ". Ada ulasan lengkap lainnya dengan topik yang sama: “
Apakah cocurrency Java dalam praktiknya masih relevan di era java 8 ”. Ini juga berisi tip tentang apa lagi yang harus Anda baca untuk benar-benar memahami topiknya. Setelah itu, Anda dapat melihat lebih dekat buku yang luar biasa seperti "
Tes Latihan Pemrogram OCA OCP JavaSE 8 ". Kami tertarik dengan bagian kedua, yaitu OCP. Dan ada tes di "∫". Buku ini berisi pertanyaan dan jawaban beserta penjelasannya. Misalnya:
Banyak orang mungkin mulai mengatakan bahwa ini hanyalah metode menghafal lainnya. Di satu sisi, ya. Di sisi lain, pertanyaan ini dapat dijawab dengan mengingat bahwa
ExecutorService
ini adalah semacam “peningkatan”
Executor
. Dan
Executor
ini dimaksudkan hanya untuk menyembunyikan metode pembuatan thread, tetapi bukan cara utama mengeksekusinya, yaitu berjalan di thread baru
Runnable
. Oleh karena itu,
execute(Callable)
tidak, karena mereka hanya menambahkan metode
ExecutorService
yang dapat mengembalikan . Seperti yang Anda lihat, kita dapat menghafal daftar metode, tetapi akan lebih mudah untuk menebaknya jika kita mengetahui sifat dari kelas itu sendiri. Nah, beberapa materi tambahan tentang topik ini:
Executor
submit
Future
#Viacheslav
GO TO FULL VERSION