Java Concurrency - Panduan Cepat
Java adalah bahasa pemrograman multi-threaded yang artinya kita dapat mengembangkan program multi-threaded menggunakan Java. Program multi-utas berisi dua atau lebih bagian yang dapat berjalan secara bersamaan dan setiap bagian dapat menangani tugas yang berbeda pada saat yang sama memanfaatkan sumber daya yang tersedia secara optimal khususnya ketika komputer Anda memiliki banyak CPU.
Menurut definisi, multitasking adalah ketika beberapa proses berbagi sumber daya pemrosesan yang umum seperti CPU. Multi-threading memperluas gagasan multitasking menjadi aplikasi di mana Anda dapat membagi operasi tertentu dalam satu aplikasi menjadi utas individu. Setiap utas dapat berjalan secara paralel. OS membagi waktu pemrosesan tidak hanya di antara aplikasi yang berbeda, tetapi juga di antara setiap utas dalam aplikasi.
Multi-threading memungkinkan Anda menulis dengan cara di mana banyak aktivitas dapat dilanjutkan secara bersamaan dalam program yang sama.
Siklus Hidup Thread
Seutas benang melewati berbagai tahapan dalam siklus hidupnya. Misalnya, utas lahir, dimulai, dijalankan, lalu mati. Diagram berikut menunjukkan siklus hidup utas lengkap.
Berikut adalah tahapan siklus hidup -
New- Utas baru memulai siklus hidupnya di status baru. Ini tetap dalam status ini sampai program memulai utas. Ini juga disebut sebagai aborn thread.
Runnable- Setelah utas yang baru lahir dimulai, utas menjadi dapat dijalankan. Untaian dalam status ini dianggap sedang menjalankan tugasnya.
Waiting- Terkadang, utas beralih ke status menunggu sementara utas menunggu utas lain melakukan tugas. Sebuah thread bertransisi kembali ke kondisi runnable hanya ketika thread lain memberi sinyal kepada thread yang menunggu untuk melanjutkan eksekusi.
Timed Waiting- Utas yang dapat dijalankan dapat memasuki status menunggu berjangka waktu untuk interval waktu tertentu. Sebuah utas dalam keadaan ini transisi kembali ke keadaan runnable ketika interval waktu itu kedaluwarsa atau ketika acara itu menunggu terjadi.
Terminated (Dead) - Utas yang dapat dijalankan memasuki status dihentikan ketika menyelesaikan tugasnya atau berakhir.
Prioritas Benang
Setiap thread Java memiliki prioritas yang membantu sistem operasi menentukan urutan thread yang dijadwalkan.
Prioritas utas Java berada dalam kisaran antara MIN_PRIORITY (konstanta 1) dan MAX_PRIORITY (konstanta 10). Secara default, setiap utas diberi prioritas NORM_PRIORITY (konstanta 5).
Utas dengan prioritas lebih tinggi lebih penting untuk program dan harus dialokasikan waktu prosesor sebelum utas dengan prioritas lebih rendah. Namun, prioritas thread tidak dapat menjamin urutan eksekusi thread dan sangat bergantung pada platform.
Buat Thread dengan Menerapkan Antarmuka yang Dapat Dijalankan
Jika kelas Anda dimaksudkan untuk dieksekusi sebagai utas, Anda dapat mencapai ini dengan mengimplementasikan Runnableantarmuka. Anda harus mengikuti tiga langkah dasar -
Langkah 1
Sebagai langkah pertama, Anda perlu mengimplementasikan metode run () yang disediakan oleh a Runnableantarmuka. Metode ini menyediakan titik masuk untuk utas dan Anda akan memasukkan logika bisnis lengkap Anda ke dalam metode ini. Berikut ini adalah sintaks sederhana dari metode run () -
public void run( )
Langkah 2
Sebagai langkah kedua, Anda akan membuat Thread objek menggunakan konstruktor berikut -
Thread(Runnable threadObj, String threadName);
Di mana, threadObj adalah turunan dari kelas yang mengimplementasikanRunnable antarmuka dan threadName adalah nama yang diberikan ke utas baru.
LANGKAH 3
Setelah objek Thread dibuat, Anda dapat memulainya dengan memanggil start()metode, yang mengeksekusi panggilan ke metode run (). Berikut ini adalah sintaks sederhana dari metode start () -
void start();
Example
Berikut adalah contoh untuk membuat utas baru dan mulai menjalankannya -
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo("Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo("Thread-2");
R2.start();
}
}
Ini akan menghasilkan hasil sebagai berikut -
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Buat Thread dengan Memperluas Kelas Thread
Cara kedua untuk membuat utas adalah membuat kelas baru yang diperluas Threadkelas menggunakan dua langkah sederhana berikut. Pendekatan ini memberikan lebih banyak fleksibilitas dalam menangani beberapa thread yang dibuat menggunakan metode yang tersedia di kelas Thread.
Langkah 1
Anda harus mengganti run( )metode yang tersedia di kelas Thread. Metode ini menyediakan titik masuk untuk utas dan Anda akan memasukkan logika bisnis lengkap Anda ke dalam metode ini. Berikut ini adalah sintaks sederhana dari metode run () -
public void run( )
Langkah 2
Setelah objek Thread dibuat, Anda dapat memulainya dengan memanggil start()metode, yang mengeksekusi panggilan ke metode run (). Berikut ini adalah sintaks sederhana dari metode start () -
void start( );
Example
Berikut adalah program sebelumnya yang ditulis ulang untuk memperpanjang Thread -
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo("Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo("Thread-2");
T2.start();
}
}
Ini akan menghasilkan hasil sebagai berikut -
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Dalam bab ini, kita akan membahas tentang berbagai aspek pengaturan lingkungan yang cocok untuk Java.
Pengaturan Lingkungan Lokal
Jika Anda masih ingin mengatur lingkungan Anda untuk bahasa pemrograman Java, maka bagian ini memandu Anda tentang cara mengunduh dan mengatur Java di komputer Anda. Berikut adalah langkah-langkah untuk mengatur lingkungan.
Java SE tersedia secara gratis dari tautan Unduh Java . Anda dapat mengunduh versi berdasarkan sistem operasi Anda.
Ikuti petunjuk untuk mengunduh Java dan menjalankan .exeuntuk menginstal Java di komputer Anda. Setelah Anda menginstal Java di komputer Anda, Anda perlu mengatur variabel lingkungan agar mengarah ke direktori instalasi yang benar -
Menyiapkan Path untuk Windows
Dengan asumsi Anda telah menginstal Java di direktori c: \ Program Files \ java \ jdk -
Klik kanan pada 'My Computer' dan pilih 'Properties'.
Klik tombol 'Variabel lingkungan' di bawah tab 'Lanjutan'.
Sekarang, ubah variabel 'Path' sehingga juga berisi path ke Java yang dapat dieksekusi. Contoh, jika jalur saat ini disetel ke 'C: \ WINDOWS \ SYSTEM32', ubah jalur Anda menjadi 'C: \ WINDOWS \ SYSTEM32; c: \ Program Files \ java \ jdk \ bin'.
Menyiapkan Path untuk Linux, UNIX, Solaris, FreeBSD
Variabel lingkungan PATH harus disetel agar mengarah ke tempat biner Java telah dipasang. Lihat dokumentasi shell Anda, jika Anda kesulitan melakukan ini.
Contoh, jika Anda menggunakan bash sebagai shell Anda, maka Anda akan menambahkan baris berikut di akhir '.bashrc: export PATH = / path / to / java: $ PATH'
Editor Java Populer
Untuk menulis program Java Anda, Anda memerlukan editor teks. Ada IDE yang lebih canggih yang tersedia di pasaran. Tetapi untuk saat ini, Anda dapat mempertimbangkan salah satu dari yang berikut -
Notepad - Pada mesin Windows, Anda dapat menggunakan editor teks sederhana seperti Notepad (Disarankan untuk tutorial ini), TextPad.
Netbeans - IDE Java yang open-source dan gratis yang dapat diunduh dari https://netbeans.org/index.html.
Eclipse - IDE Java yang dikembangkan oleh komunitas open-source eclipse dan dapat diunduh dari https://www.eclipse.org/.
Core Java menyediakan kendali penuh atas program multithread. Anda dapat mengembangkan program multithread yang dapat ditangguhkan, dilanjutkan, atau dihentikan sepenuhnya berdasarkan kebutuhan Anda. Ada berbagai metode statis yang dapat Anda gunakan pada objek thread untuk mengontrol perilakunya. Tabel berikut mencantumkan metode tersebut -
Sr.No. | Metode & Deskripsi |
---|---|
1 | public void suspend() Metode ini menempatkan utas dalam status ditangguhkan dan dapat dilanjutkan menggunakan metode resume (). |
2 | public void stop() Metode ini menghentikan utas sepenuhnya. |
3 | public void resume() Metode ini melanjutkan utas, yang ditangguhkan menggunakan metode suspend (). |
4 | public void wait() Menyebabkan utas saat ini menunggu hingga utas lain memanggil notify (). |
5 | public void notify() Membangunkan satu utas yang menunggu di monitor objek ini. |
Ketahuilah bahwa versi terbaru Java tidak lagi menggunakan metode suspend (), resume (), dan stop () sehingga Anda perlu menggunakan alternatif yang tersedia.
Contoh
class RunnableDemo implements Runnable {
public Thread t;
private String threadName;
boolean suspended = false;
RunnableDemo(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 10; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(300);
synchronized(this) {
while(suspended) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
void suspend() {
suspended = true;
}
synchronized void resume() {
suspended = false;
notify();
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo("Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo("Thread-2");
R2.start();
try {
Thread.sleep(1000);
R1.suspend();
System.out.println("Suspending First Thread");
Thread.sleep(1000);
R1.resume();
System.out.println("Resuming First Thread");
R2.suspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
R2.resume();
System.out.println("Resuming thread Two");
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
} try {
System.out.println("Waiting for threads to finish.");
R1.t.join();
R2.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Program di atas menghasilkan keluaran sebagai berikut -
Keluaran
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 10
Running Thread-2
Thread: Thread-2, 10
Thread: Thread-1, 9
Thread: Thread-2, 9
Thread: Thread-1, 8
Thread: Thread-2, 8
Thread: Thread-1, 7
Thread: Thread-2, 7
Suspending First Thread
Thread: Thread-2, 6
Thread: Thread-2, 5
Thread: Thread-2, 4
Resuming First Thread
Suspending thread Two
Thread: Thread-1, 6
Thread: Thread-1, 5
Thread: Thread-1, 4
Thread: Thread-1, 3
Resuming thread Two
Thread: Thread-2, 3
Waiting for threads to finish.
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Main thread exiting.
Jika Anda mengetahui komunikasi antarproses maka akan mudah bagi Anda untuk memahami komunikasi interthread. Komunikasi interthread penting ketika Anda mengembangkan aplikasi di mana dua atau lebih utas bertukar beberapa informasi.
Ada tiga metode sederhana dan sedikit trik yang memungkinkan komunikasi utas. Ketiga metode tersebut tercantum di bawah ini -
Sr.No. | Metode & Deskripsi |
---|---|
1 | public void wait() Menyebabkan utas saat ini menunggu hingga utas lain memanggil notify (). |
2 | public void notify() Membangunkan satu utas yang menunggu di monitor objek ini. |
3 | public void notifyAll() Membangunkan semua utas yang memanggil wait () pada objek yang sama. |
Metode ini telah diterapkan sebagai finalmetode di Object, sehingga tersedia di semua kelas. Ketiga metode hanya dapat dipanggil dari dalam asynchronized konteks.
Contoh
Contoh ini menunjukkan bagaimana dua utas dapat berkomunikasi menggunakan wait() dan notify()metode. Anda dapat membuat sistem yang kompleks dengan menggunakan konsep yang sama.
class Chat {
boolean flag = false;
public synchronized void Question(String msg) {
if (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(msg);
flag = true;
notify();
}
public synchronized void Answer(String msg) {
if (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(msg);
flag = false;
notify();
}
}
class T1 implements Runnable {
Chat m;
String[] s1 = { "Hi", "How are you ?", "I am also doing fine!" };
public T1(Chat m1) {
this.m = m1;
new Thread(this, "Question").start();
}
public void run() {
for (int i = 0; i < s1.length; i++) {
m.Question(s1[i]);
}
}
}
class T2 implements Runnable {
Chat m;
String[] s2 = { "Hi", "I am good, what about you?", "Great!" };
public T2(Chat m2) {
this.m = m2;
new Thread(this, "Answer").start();
}
public void run() {
for (int i = 0; i < s2.length; i++) {
m.Answer(s2[i]);
}
}
}
public class TestThread {
public static void main(String[] args) {
Chat m = new Chat();
new T1(m);
new T2(m);
}
}
Ketika program di atas dipenuhi dan dijalankan, ini menghasilkan hasil sebagai berikut -
Keluaran
Hi
Hi
How are you ?
I am good, what about you?
I am also doing fine!
Great!
Contoh di atas telah diambil dan kemudian diubah dari [https://stackoverflow.com/questions/2170520/inter-thread-communication-in-java]
Contoh Multithreading dengan Sinkronisasi
Berikut adalah contoh yang sama yang mencetak nilai counter secara berurutan dan setiap kali kita menjalankannya, menghasilkan hasil yang sama.
Contoh
class PrintDemo {
public void printCount() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Counter --- " + i );
}
} catch (Exception e) {
System.out.println("Thread interrupted.");
}
}
}
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
PrintDemo PD;
ThreadDemo(String name, PrintDemo pd) {
threadName = name;
PD = pd;
}
public void run() {
synchronized(PD) {
PD.printCount();
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
PrintDemo PD = new PrintDemo();
ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD);
ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD);
T1.start();
T2.start();
// wait for threads to end
try {
T1.join();
T2.join();
} catch (Exception e) {
System.out.println("Interrupted");
}
}
}
Ini menghasilkan hasil yang sama setiap kali Anda menjalankan program ini -
Keluaran
Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 1 exiting.
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.
Deadlock menggambarkan situasi di mana dua atau lebih utas diblokir selamanya, menunggu satu sama lain. Kebuntuan terjadi ketika beberapa utas membutuhkan kunci yang sama tetapi mendapatkannya dalam urutan yang berbeda. Program multithread Java mungkin mengalami kondisi kebuntuan karenasynchronizedkata kunci menyebabkan utas yang menjalankan memblokir sambil menunggu kunci, atau monitor, terkait dengan objek yang ditentukan. Berikut ini contohnya.
Contoh
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
Ketika Anda mengkompilasi dan menjalankan program di atas, Anda menemukan situasi kebuntuan dan berikut adalah keluaran yang dihasilkan oleh program -
Keluaran
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...
Program di atas akan hang selamanya karena tak satu pun dari utas dalam posisi untuk melanjutkan dan menunggu satu sama lain untuk melepaskan kunci, sehingga Anda dapat keluar dari program dengan menekan CTRL + C.
Contoh Solusi Kebuntuan
Mari ubah urutan kunci dan jalankan program yang sama untuk melihat apakah kedua utas masih menunggu satu sama lain -
Contoh
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
Jadi hanya dengan mengubah urutan kunci mencegah program mengalami situasi kebuntuan dan selesai dengan hasil sebagai berikut -
Keluaran
Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...
Contoh di atas adalah untuk memperjelas konsepnya, namun, ini adalah konsep yang kompleks dan Anda harus menyelami lebih dalam sebelum Anda mengembangkan aplikasi untuk menghadapi situasi kebuntuan.
Kelas ThreadLocal digunakan untuk membuat variabel lokal thread yang hanya dapat dibaca dan ditulis oleh thread yang sama. Misalnya, jika dua thread mengakses kode yang memiliki referensi ke variabel threadLocal yang sama, maka setiap thread tidak akan melihat modifikasi apa pun pada variabel threadLocal yang dilakukan oleh thread lain.
Metode ThreadLocal
Berikut adalah daftar metode penting yang tersedia di kelas ThreadLocal.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public T get() Mengembalikan nilai dalam salinan utas saat ini dari variabel utas-lokal ini. |
2 | protected T initialValue() Menampilkan "nilai awal" thread saat ini untuk variabel thread-lokal ini. |
3 | public void remove() Menghapus nilai thread saat ini untuk variabel thread-lokal ini. |
4 | public void set(T value) Menyetel salinan utas saat ini dari variabel utas-lokal ini ke nilai yang ditentukan. |
Contoh
Program TestThread berikut mendemonstrasikan beberapa metode kelas ThreadLocal ini. Di sini kita telah menggunakan dua variabel counter, satu variabel normal dan satu lagi adalah ThreadLocal.
class RunnableDemo implements Runnable {
int counter;
ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<Integer>();
public void run() {
counter++;
if(threadLocalCounter.get() != null) {
threadLocalCounter.set(threadLocalCounter.get().intValue() + 1);
} else {
threadLocalCounter.set(0);
}
System.out.println("Counter: " + counter);
System.out.println("threadLocalCounter: " + threadLocalCounter.get());
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo commonInstance = new RunnableDemo();
Thread t1 = new Thread(commonInstance);
Thread t2 = new Thread(commonInstance);
Thread t3 = new Thread(commonInstance);
Thread t4 = new Thread(commonInstance);
t1.start();
t2.start();
t3.start();
t4.start();
// wait for threads to end
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (Exception e) {
System.out.println("Interrupted");
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Counter: 1
threadLocalCounter: 0
Counter: 2
threadLocalCounter: 0
Counter: 3
threadLocalCounter: 0
Counter: 4
threadLocalCounter: 0
Anda dapat melihat nilai penghitung ditingkatkan oleh setiap utas, tetapi threadLocalCounter tetap 0 untuk setiap utas.
Java.util.concurrent.ThreadLocalRandom adalah kelas utilitas yang diperkenalkan dari jdk 1.7 dan seterusnya dan berguna ketika beberapa utas atau ForkJoinTasks diperlukan untuk menghasilkan angka acak. Itu meningkatkan kinerja dan memiliki lebih sedikit pertentangan daripada metode Math.random ().
Metode ThreadLocalRandom
Berikut adalah daftar metode penting yang tersedia di kelas ThreadLocalRandom.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public static ThreadLocalRandom current() Menampilkan ThreadLocalRandom thread saat ini. |
2 | protected int next(int bits) Menghasilkan nomor pseudorandom berikutnya. |
3 | public double nextDouble(double n) Menampilkan pseudorandom, nilai ganda yang didistribusikan secara seragam antara 0 (inklusif) dan nilai yang ditentukan (eksklusif). |
4 | public double nextDouble(double least, double bound) Mengembalikan pseudorandom, nilai terdistribusi seragam antara nilai terkecil yang diberikan (inklusif) dan terikat (eksklusif). |
5 | public int nextInt(int least, int bound) Mengembalikan pseudorandom, nilai terdistribusi seragam antara nilai terkecil yang diberikan (inklusif) dan terikat (eksklusif). |
6 | public long nextLong(long n) Mengembalikan pseudorandom, nilai terdistribusi seragam antara 0 (inklusif) dan nilai yang ditentukan (eksklusif). |
7 | public long nextLong(long least, long bound) Mengembalikan pseudorandom, nilai terdistribusi seragam antara nilai terkecil yang diberikan (inklusif) dan terikat (eksklusif). |
8 | public void setSeed(long seed) Melempar UnsupportedOperationException. |
Contoh
Program TestThread berikut mendemonstrasikan beberapa metode antarmuka Lock ini. Di sini kami telah menggunakan lock () untuk mendapatkan kunci dan buka kunci () untuk membuka kunci.
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ThreadLocalRandom;
public class TestThread {
public static void main(final String[] arguments) {
System.out.println("Random Integer: " + new Random().nextInt());
System.out.println("Seeded Random Integer: " + new Random(15).nextInt());
System.out.println(
"Thread Local Random Integer: " + ThreadLocalRandom.current().nextInt());
final ThreadLocalRandom random = ThreadLocalRandom.current();
random.setSeed(15); //exception will come as seeding is not allowed in ThreadLocalRandom.
System.out.println("Seeded Thread Local Random Integer: " + random.nextInt());
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Random Integer: 1566889198
Seeded Random Integer: -1159716814
Thread Local Random Integer: 358693993
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.concurrent.ThreadLocalRandom.setSeed(Unknown Source)
at TestThread.main(TestThread.java:21)
Di sini kami telah menggunakan kelas ThreadLocalRandom dan Random untuk mendapatkan nomor acak.
Antarmuka java.util.concurrent.locks.Lock digunakan sebagai mekanisme sinkronisasi utas yang mirip dengan blok tersinkronisasi. Mekanisme Penguncian baru lebih fleksibel dan memberikan lebih banyak opsi daripada blok tersinkronisasi. Perbedaan utama antara Kunci dan blok tersinkronisasi adalah sebagai berikut:
Guarantee of sequence- Blok tersinkronisasi tidak memberikan jaminan urutan apa pun di mana thread yang menunggu akan diberi akses. Antarmuka kunci menanganinya.
No timeout- Blok tersinkronisasi tidak memiliki opsi batas waktu jika kunci tidak diberikan. Antarmuka kunci menyediakan opsi seperti itu.
Single method - Blok tersinkronisasi harus sepenuhnya terkandung dalam satu metode sedangkan metode antarmuka kunci lock () dan unlock () dapat dipanggil dalam metode yang berbeda.
Metode Kunci
Berikut adalah daftar metode penting yang tersedia di kelas Lock.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public void lock() Memperoleh kunci. |
2 | public void lockInterruptibly() Memperoleh kunci kecuali utas saat ini terputus. |
3 | public Condition newCondition() Mengembalikan contoh Kondisi baru yang terikat ke contoh Lock ini. |
4 | public boolean tryLock() Memperoleh kunci hanya jika gratis pada saat pemanggilan. |
5 | public boolean tryLock() Memperoleh kunci hanya jika gratis pada saat pemanggilan. |
6 | public boolean tryLock(long time, TimeUnit unit) Memperoleh kunci jika kosong dalam waktu tunggu yang diberikan dan utas saat ini belum terputus. |
7 | public void unlock() Lepaskan kunci. |
Contoh
Program TestThread berikut mendemonstrasikan beberapa metode antarmuka Lock ini. Di sini kami telah menggunakan lock () untuk mendapatkan kunci dan buka kunci () untuk membuka kunci.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class PrintDemo {
private final Lock queueLock = new ReentrantLock();
public void print() {
queueLock.lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName()
+ " Time Taken " + (duration / 1000) + " seconds.");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.printf(
"%s printed the document successfully.\n", Thread.currentThread().getName());
queueLock.unlock();
}
}
}
class ThreadDemo extends Thread {
PrintDemo printDemo;
ThreadDemo(String name, PrintDemo printDemo) {
super(name);
this.printDemo = printDemo;
}
@Override
public void run() {
System.out.printf(
"%s starts printing a document\n", Thread.currentThread().getName());
printDemo.print();
}
}
public class TestThread {
public static void main(String args[]) {
PrintDemo PD = new PrintDemo();
ThreadDemo t1 = new ThreadDemo("Thread - 1 ", PD);
ThreadDemo t2 = new ThreadDemo("Thread - 2 ", PD);
ThreadDemo t3 = new ThreadDemo("Thread - 3 ", PD);
ThreadDemo t4 = new ThreadDemo("Thread - 4 ", PD);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Thread - 1 starts printing a document
Thread - 4 starts printing a document
Thread - 3 starts printing a document
Thread - 2 starts printing a document
Thread - 1 Time Taken 4 seconds.
Thread - 1 printed the document successfully.
Thread - 4 Time Taken 3 seconds.
Thread - 4 printed the document successfully.
Thread - 3 Time Taken 5 seconds.
Thread - 3 printed the document successfully.
Thread - 2 Time Taken 4 seconds.
Thread - 2 printed the document successfully.
Kami telah menggunakan kelas ReentrantLock sebagai implementasi antarmuka Lock di sini. Kelas ReentrantLock memungkinkan utas mengunci metode meskipun metode tersebut sudah dikunci di metode lain.
Antarmuka java.util.concurrent.locks.ReadWriteLock memungkinkan beberapa utas dibaca sekaligus, tetapi hanya satu utas yang dapat menulis dalam satu waktu.
Read Lock - Jika tidak ada utas yang mengunci ReadWriteLock untuk menulis, maka beberapa utas dapat mengakses kunci baca.
Write Lock - Jika tidak ada utas yang membaca atau menulis, maka satu utas dapat mengakses kunci tulis.
Metode Kunci
Berikut adalah daftar metode penting yang tersedia di kelas Lock.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public Lock readLock() Mengembalikan kunci yang digunakan untuk membaca. |
2 | public Lock writeLock() Mengembalikan kunci yang digunakan untuk menulis. |
Contoh
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class TestThread {
private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
private static String message = "a";
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new WriterA());
t1.setName("Writer A");
Thread t2 = new Thread(new WriterB());
t2.setName("Writer B");
Thread t3 = new Thread(new Reader());
t3.setName("Reader");
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
}
static class Reader implements Runnable {
public void run() {
if(lock.isWriteLocked()) {
System.out.println("Write Lock Present.");
}
lock.readLock().lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName()
+ " Time Taken " + (duration / 1000) + " seconds.");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() +": "+ message );
lock.readLock().unlock();
}
}
}
static class WriterA implements Runnable {
public void run() {
lock.writeLock().lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName()
+ " Time Taken " + (duration / 1000) + " seconds.");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
message = message.concat("a");
lock.writeLock().unlock();
}
}
}
static class WriterB implements Runnable {
public void run() {
lock.writeLock().lock();
try {
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName()
+ " Time Taken " + (duration / 1000) + " seconds.");
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
message = message.concat("b");
lock.writeLock().unlock();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Writer A Time Taken 6 seconds.
Write Lock Present.
Writer B Time Taken 2 seconds.
Reader Time Taken 0 seconds.
Reader: aab
Antarmuka java.util.concurrent.locks.Condition menyediakan kemampuan utas untuk menangguhkan eksekusinya, hingga kondisi yang diberikan benar. Objek Kondisi harus terikat ke Lock dan diperoleh menggunakan metode newCondition ().
Metode Kondisi
Berikut adalah daftar metode penting yang tersedia di kelas Kondisi.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public void await() Menyebabkan utas saat ini menunggu hingga diberi sinyal atau terputus. |
2 | public boolean await(long time, TimeUnit unit) Menyebabkan utas saat ini menunggu hingga diberi sinyal atau terputus, atau waktu tunggu yang ditentukan berlalu. |
3 | public long awaitNanos(long nanosTimeout) Menyebabkan utas saat ini menunggu hingga diberi sinyal atau terputus, atau waktu tunggu yang ditentukan berlalu. |
4 | public long awaitUninterruptibly() Menyebabkan utas saat ini menunggu hingga diberi sinyal. |
5 | public long awaitUntil() Menyebabkan utas saat ini menunggu hingga diberi sinyal atau terputus, atau tenggat waktu yang ditentukan berlalu. |
6 | public void signal() Bangun satu utas menunggu. |
7 | public void signalAll() Bangunkan semua utas menunggu. |
Contoh
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestThread {
public static void main(String[] args) throws InterruptedException {
ItemQueue itemQueue = new ItemQueue(10);
//Create a producer and a consumer.
Thread producer = new Producer(itemQueue);
Thread consumer = new Consumer(itemQueue);
//Start both threads.
producer.start();
consumer.start();
//Wait for both threads to terminate.
producer.join();
consumer.join();
}
static class ItemQueue {
private Object[] items = null;
private int current = 0;
private int placeIndex = 0;
private int removeIndex = 0;
private final Lock lock;
private final Condition isEmpty;
private final Condition isFull;
public ItemQueue(int capacity) {
this.items = new Object[capacity];
lock = new ReentrantLock();
isEmpty = lock.newCondition();
isFull = lock.newCondition();
}
public void add(Object item) throws InterruptedException {
lock.lock();
while(current >= items.length)
isFull.await();
items[placeIndex] = item;
placeIndex = (placeIndex + 1) % items.length;
++current;
//Notify the consumer that there is data available.
isEmpty.signal();
lock.unlock();
}
public Object remove() throws InterruptedException {
Object item = null;
lock.lock();
while(current <= 0) {
isEmpty.await();
}
item = items[removeIndex];
removeIndex = (removeIndex + 1) % items.length;
--current;
//Notify the producer that there is space available.
isFull.signal();
lock.unlock();
return item;
}
public boolean isEmpty() {
return (items.length == 0);
}
}
static class Producer extends Thread {
private final ItemQueue queue;
public Producer(ItemQueue queue) {
this.queue = queue;
}
@Override
public void run() {
String[] numbers =
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};
try {
for(String number: numbers) {
System.out.println("[Producer]: " + number);
}
queue.add(null);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
static class Consumer extends Thread {
private final ItemQueue queue;
public Consumer(ItemQueue queue) {
this.queue = queue;
}
@Override
public void run() {
try {
do {
Object number = queue.remove();
System.out.println("[Consumer]: " + number);
if(number == null) {
return;
}
} while(!queue.isEmpty());
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
[Producer]: 1
[Producer]: 2
[Producer]: 3
[Producer]: 4
[Producer]: 5
[Producer]: 6
[Producer]: 7
[Producer]: 8
[Producer]: 9
[Producer]: 10
[Producer]: 11
[Producer]: 12
[Consumer]: null
Kelas java.util.concurrent.atomic.AtomicInteger menyediakan operasi pada nilai int yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicInteger mendukung operasi atom pada variabel int yang mendasari. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicInteger
Berikut adalah daftar metode penting yang tersedia di kelas AtomicInteger.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public int addAndGet(int delta) Secara atomis menambahkan nilai yang diberikan ke nilai saat ini. |
2 | public boolean compareAndSet(int expect, int update) Secara atomis menetapkan nilai ke nilai yang diperbarui jika nilai saat ini sama dengan nilai yang diharapkan. |
3 | public int decrementAndGet() Secara atomis mengurangi satu nilai saat ini. |
4 | public double doubleValue() Mengembalikan nilai dari angka yang ditentukan sebagai ganda. |
5 | public float floatValue() Mengembalikan nilai dari angka yang ditentukan sebagai float. |
6 | public int get() Mendapat nilai saat ini. |
7 | public int getAndAdd(int delta) Secara atomiclly menambahkan nilai yang diberikan ke nilai saat ini. |
8 | public int getAndDecrement() Secara atomis mengurangi satu nilai saat ini. |
9 | public int getAndIncrement() Secara atomis bertambah satu nilai saat ini. |
10 | public int getAndSet(int newValue) Secara atomis disetel ke nilai yang diberikan dan mengembalikan nilai lama. |
11 | public int incrementAndGet() Secara atomis bertambah satu nilai saat ini. |
12 | public int intValue() Mengembalikan nilai dari angka yang ditentukan sebagai int. |
13 | public void lazySet(int newValue) Akhirnya disetel ke nilai yang diberikan. |
14 | public long longValue() Mengembalikan nilai dari angka yang ditentukan sebagai panjang. |
15 | public void set(int newValue) Set ke nilai yang diberikan. |
16 | public String toString() Mengembalikan representasi String dari nilai saat ini. |
17 | public boolean weakCompareAndSet(int expect, int update) Secara atomis menetapkan nilai ke nilai yang diperbarui jika nilai saat ini sama dengan nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan implementasi penghitung yang tidak aman di lingkungan berbasis thread.
public class TestThread {
static class Counter {
private int c = 0;
public void increment() {
c++;
}
public int value() {
return c;
}
}
public static void main(final String[] arguments) throws InterruptedException {
final Counter counter = new Counter();
//1000 threads
for(int i = 0; i < 1000 ; i++) {
new Thread(new Runnable() {
public void run() {
counter.increment();
}
}).start();
}
Thread.sleep(6000);
System.out.println("Final number (should be 1000): " + counter.value());
}
}
Ini dapat menghasilkan hasil sebagai berikut tergantung pada kecepatan komputer dan jalinan benang.
Keluaran
Final number (should be 1000): 1000
Contoh
import java.util.concurrent.atomic.AtomicInteger;
public class TestThread {
static class Counter {
private AtomicInteger c = new AtomicInteger(0);
public void increment() {
c.getAndIncrement();
}
public int value() {
return c.get();
}
}
public static void main(final String[] arguments) throws InterruptedException {
final Counter counter = new Counter();
//1000 threads
for(int i = 0; i < 1000 ; i++) {
new Thread(new Runnable() {
public void run() {
counter.increment();
}
}).start();
}
Thread.sleep(6000);
System.out.println("Final number (should be 1000): " + counter.value());
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Final number (should be 1000): 1000
Kelas java.util.concurrent.atomic.AtomicLong menyediakan operasi pada nilai panjang yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicLong mendukung operasi atom pada variabel panjang yang mendasarinya. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicLong
Berikut adalah daftar metode penting yang tersedia di kelas AtomicLong.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public long addAndGet(long delta) Secara atomis menambahkan nilai yang diberikan ke nilai saat ini. |
2 | public boolean compareAndSet(long expect, long update) Secara atomis menetapkan nilai ke nilai yang diperbarui jika nilai saat ini sama dengan nilai yang diharapkan. |
3 | public long decrementAndGet() Secara atomis mengurangi satu nilai saat ini. |
4 | public double doubleValue() Mengembalikan nilai dari angka yang ditentukan sebagai ganda. |
5 | public float floatValue() Mengembalikan nilai dari angka yang ditentukan sebagai float. |
6 | public long get() Mendapat nilai saat ini. |
7 | public long getAndAdd(long delta) Secara atomiclly menambahkan nilai yang diberikan ke nilai saat ini. |
8 | public long getAndDecrement() Secara atomis mengurangi satu nilai saat ini. |
9 | public long getAndIncrement() Secara atomis bertambah satu nilai saat ini. |
10 | public long getAndSet(long newValue) Secara atomis disetel ke nilai yang diberikan dan mengembalikan nilai lama. |
11 | public long incrementAndGet() Secara atomis bertambah satu nilai saat ini. |
12 | public int intValue() Mengembalikan nilai dari angka yang ditentukan sebagai int. |
13 | public void lazySet(long newValue) Akhirnya disetel ke nilai yang diberikan. |
14 | public long longValue() Mengembalikan nilai dari angka yang ditentukan sebagai panjang. |
15 | public void set(long newValue) Set ke nilai yang diberikan. |
16 | public String toString() Mengembalikan representasi String dari nilai saat ini. |
17 | public boolean weakCompareAndSet(long expect, long update) Secara atomis menetapkan nilai ke nilai yang diperbarui jika nilai saat ini sama dengan nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan implementasi penghitung yang aman menggunakan AtomicLong di lingkungan berbasis utas.
import java.util.concurrent.atomic.AtomicLong;
public class TestThread {
static class Counter {
private AtomicLong c = new AtomicLong(0);
public void increment() {
c.getAndIncrement();
}
public long value() {
return c.get();
}
}
public static void main(final String[] arguments) throws InterruptedException {
final Counter counter = new Counter();
//1000 threads
for(int i = 0; i < 1000 ; i++) {
new Thread(new Runnable() {
public void run() {
counter.increment();
}
}).start();
}
Thread.sleep(6000);
System.out.println("Final number (should be 1000): " + counter.value());
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Final number (should be 1000): 1000
Kelas java.util.concurrent.atomic.AtomicBoolean menyediakan operasi pada nilai boolean yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicBoolean mendukung operasi atom pada variabel boolean yang mendasarinya. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicBoolean
Berikut adalah daftar metode penting yang tersedia di kelas AtomicBoolean.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public boolean compareAndSet(boolean expect, boolean update) Secara atomis menetapkan nilai ke nilai pembaruan yang diberikan jika nilai saat ini == nilai yang diharapkan. |
2 | public boolean get() Mengembalikan nilai saat ini. |
3 | public boolean getAndSet(boolean newValue) Secara atomis disetel ke nilai yang diberikan dan mengembalikan nilai sebelumnya. |
4 | public void lazySet(boolean newValue) Akhirnya disetel ke nilai yang diberikan. |
5 | public void set(boolean newValue) Set tanpa syarat ke nilai yang diberikan. |
6 | public String toString() Mengembalikan representasi String dari nilai saat ini. |
7 | public boolean weakCompareAndSet(boolean expect, boolean update) Secara atomis menetapkan nilai ke nilai pembaruan yang diberikan jika nilai saat ini == nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan penggunaan variabel AtomicBoolean di lingkungan berbasis thread.
import java.util.concurrent.atomic.AtomicBoolean;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
new Thread("Thread 1") {
public void run() {
while(true) {
System.out.println(Thread.currentThread().getName()
+" Waiting for Thread 2 to set Atomic variable to true. Current value is "
+ atomicBoolean.get());
if(atomicBoolean.compareAndSet(true, false)) {
System.out.println("Done!");
break;
}
}
};
}.start();
new Thread("Thread 2") {
public void run() {
System.out.println(Thread.currentThread().getName() +
", Atomic Variable: " +atomicBoolean.get());
System.out.println(Thread.currentThread().getName() +
" is setting the variable to true ");
atomicBoolean.set(true);
System.out.println(Thread.currentThread().getName() +
", Atomic Variable: " +atomicBoolean.get());
};
}.start();
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 2, Atomic Variable: false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 2 is setting the variable to true
Thread 2, Atomic Variable: true
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Done!
Kelas java.util.concurrent.atomic.AtomicReference menyediakan operasi pada referensi objek yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicReference mendukung operasi atom pada variabel referensi objek yang mendasarinya. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicReference
Berikut adalah daftar metode penting yang tersedia di kelas AtomicReference.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public boolean compareAndSet(V expect, V update) Secara atomis menetapkan nilai ke nilai pembaruan yang diberikan jika nilai saat ini == nilai yang diharapkan. |
2 | public boolean get() Mengembalikan nilai saat ini. |
3 | public boolean getAndSet(V newValue) Secara atomis disetel ke nilai yang diberikan dan mengembalikan nilai sebelumnya. |
4 | public void lazySet(V newValue) Akhirnya disetel ke nilai yang diberikan. |
5 | public void set(V newValue) Set tanpa syarat ke nilai yang diberikan. |
6 | public String toString() Mengembalikan representasi String dari nilai saat ini. |
7 | public boolean weakCompareAndSet(V expect, V update) Secara atomis menetapkan nilai ke nilai pembaruan yang diberikan jika nilai saat ini == nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan penggunaan variabel AtomicReference di lingkungan berbasis thread.
import java.util.concurrent.atomic.AtomicReference;
public class TestThread {
private static String message = "hello";
private static AtomicReference<String> atomicReference;
public static void main(final String[] arguments) throws InterruptedException {
atomicReference = new AtomicReference<String>(message);
new Thread("Thread 1") {
public void run() {
atomicReference.compareAndSet(message, "Thread 1");
message = message.concat("-Thread 1!");
};
}.start();
System.out.println("Message is: " + message);
System.out.println("Atomic Reference of Message is: " + atomicReference.get());
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Message is: hello
Atomic Reference of Message is: Thread 1
Kelas java.util.concurrent.atomic.AtomicIntegerArray menyediakan operasi pada larik int yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicIntegerArray mendukung operasi atom pada variabel int array yang mendasari. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicIntegerArray
Berikut adalah daftar metode penting yang tersedia di kelas AtomicIntegerArray.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public int addAndGet(int i, int delta) Secara atomis menambahkan nilai yang diberikan ke elemen pada indeks i. |
2 | public boolean compareAndSet(int i, int expect, int update) Secara atomis menyetel elemen di posisi i ke nilai yang diperbarui jika nilai saat ini == nilai yang diharapkan. |
3 | public int decrementAndGet(int i) Secara atomik mengurangi satu elemen pada indeks i. |
4 | public int get(int i) Mendapat nilai saat ini pada posisi i. |
5 | public int getAndAdd(int i, int delta) Secara atomis menambahkan nilai yang diberikan ke elemen pada indeks i. |
6 | public int getAndDecrement(int i) Secara atomik mengurangi satu elemen pada indeks i. |
7 | public int getAndIncrement(int i) Secara atomis bertambah satu elemen pada indeks i. |
8 | public int getAndSet(int i, int newValue) Secara atomis menyetel elemen di posisi i ke nilai yang diberikan dan mengembalikan nilai lama. |
9 | public int incrementAndGet(int i) Secara atomis bertambah satu elemen pada indeks i. |
10 | public void lazySet(int i, int newValue) Akhirnya menetapkan elemen di posisi i ke nilai yang diberikan. |
11 | public int length() Mengembalikan panjang larik. |
12 | public void set(int i, int newValue) Setel elemen di posisi i ke nilai yang diberikan. |
13 | public String toString() Mengembalikan representasi String dari nilai-nilai array saat ini. |
14 | public boolean weakCompareAndSet(int i, int expect, int update) Secara atomis menyetel elemen di posisi i ke nilai yang diperbarui jika nilai saat ini == nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan penggunaan variabel AtomicIntegerArray di lingkungan berbasis thread.
import java.util.concurrent.atomic.AtomicIntegerArray;
public class TestThread {
private static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
public static void main(final String[] arguments) throws InterruptedException {
for (int i = 0; i<atomicIntegerArray.length(); i++) {
atomicIntegerArray.set(i, 1);
}
Thread t1 = new Thread(new Increment());
Thread t2 = new Thread(new Compare());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Values: ");
for (int i = 0; i<atomicIntegerArray.length(); i++) {
System.out.print(atomicIntegerArray.get(i) + " ");
}
}
static class Increment implements Runnable {
public void run() {
for(int i = 0; i<atomicIntegerArray.length(); i++) {
int add = atomicIntegerArray.incrementAndGet(i);
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", value: "+ add);
}
}
}
static class Compare implements Runnable {
public void run() {
for(int i = 0; i<atomicIntegerArray.length(); i++) {
boolean swapped = atomicIntegerArray.compareAndSet(i, 2, 3);
if(swapped) {
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", value: 3");
}
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Thread 10, index 0, value: 2
Thread 10, index 1, value: 2
Thread 10, index 2, value: 2
Thread 11, index 0, value: 3
Thread 10, index 3, value: 2
Thread 11, index 1, value: 3
Thread 11, index 2, value: 3
Thread 10, index 4, value: 2
Thread 11, index 3, value: 3
Thread 10, index 5, value: 2
Thread 10, index 6, value: 2
Thread 11, index 4, value: 3
Thread 10, index 7, value: 2
Thread 11, index 5, value: 3
Thread 10, index 8, value: 2
Thread 11, index 6, value: 3
Thread 10, index 9, value: 2
Thread 11, index 7, value: 3
Thread 11, index 8, value: 3
Thread 11, index 9, value: 3
Values:
3 3 3 3 3 3 3 3 3 3
Kelas java.util.concurrent.atomic.AtomicLongArray menyediakan operasi pada larik panjang yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicLongArray mendukung operasi atom pada variabel array panjang yang mendasarinya. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicLongArray
Berikut adalah daftar metode penting yang tersedia di kelas AtomicLongArray.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public long addAndGet(int i, long delta) Secara atomis menambahkan nilai yang diberikan ke elemen pada indeks i. |
2 | public boolean compareAndSet(int i, long expect, long update) Secara atomis menyetel elemen di posisi i ke nilai yang diperbarui jika nilai saat ini == nilai yang diharapkan. |
3 | public long decrementAndGet(int i) Secara atomik mengurangi satu elemen pada indeks i. |
4 | public long get(int i) Mendapat nilai saat ini pada posisi i. |
5 | public long getAndAdd(int i, long delta) Secara atomis menambahkan nilai yang diberikan ke elemen pada indeks i. |
6 | public long getAndDecrement(int i) Secara atomik mengurangi satu elemen pada indeks i. |
7 | public long getAndIncrement(int i) Secara atomis bertambah satu elemen pada indeks i. |
8 | public long getAndSet(int i, long newValue) Secara atomis menyetel elemen di posisi i ke nilai yang diberikan dan mengembalikan nilai lama. |
9 | public long incrementAndGet(int i) Secara atomis bertambah satu elemen pada indeks i. |
10 | public void lazySet(int i, long newValue) Akhirnya menetapkan elemen di posisi i ke nilai yang diberikan. |
11 | public int length() Mengembalikan panjang larik. |
12 | public void set(int i, long newValue) Setel elemen di posisi i ke nilai yang diberikan. |
13 | public String toString() Mengembalikan representasi String dari nilai-nilai array saat ini. |
14 | public boolean weakCompareAndSet(int i, long expect, long update) Secara atomis menyetel elemen di posisi i ke nilai yang diperbarui jika nilai saat ini == nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan penggunaan variabel AtomicIntegerArray di lingkungan berbasis thread.
import java.util.concurrent.atomic.AtomicLongArray;
public class TestThread {
private static AtomicLongArray atomicLongArray = new AtomicLongArray(10);
public static void main(final String[] arguments) throws InterruptedException {
for (int i = 0; i<atomicLongArray.length(); i++) {
atomicLongArray.set(i, 1);
}
Thread t1 = new Thread(new Increment());
Thread t2 = new Thread(new Compare());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Values: ");
for (int i = 0; i<atomicLongArray.length(); i++) {
System.out.print(atomicLongArray.get(i) + " ");
}
}
static class Increment implements Runnable {
public void run() {
for(int i = 0; i<atomicLongArray.length(); i++) {
long add = atomicLongArray.incrementAndGet(i);
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", value: "+ add);
}
}
}
static class Compare implements Runnable {
public void run() {
for(int i = 0; i<atomicLongArray.length(); i++) {
boolean swapped = atomicLongArray.compareAndSet(i, 2, 3);
if(swapped) {
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", value: 3");
}
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Thread 9, index 0, value: 2
Thread 10, index 0, value: 3
Thread 9, index 1, value: 2
Thread 9, index 2, value: 2
Thread 9, index 3, value: 2
Thread 9, index 4, value: 2
Thread 10, index 1, value: 3
Thread 9, index 5, value: 2
Thread 10, index 2, value: 3
Thread 9, index 6, value: 2
Thread 10, index 3, value: 3
Thread 9, index 7, value: 2
Thread 10, index 4, value: 3
Thread 9, index 8, value: 2
Thread 9, index 9, value: 2
Thread 10, index 5, value: 3
Thread 10, index 6, value: 3
Thread 10, index 7, value: 3
Thread 10, index 8, value: 3
Thread 10, index 9, value: 3
Values:
3 3 3 3 3 3 3 3 3 3
Kelas java.util.concurrent.atomic.AtomicReferenceArray menyediakan operasi pada larik referensi yang mendasari yang dapat dibaca dan ditulis secara atomik, dan juga berisi operasi atom tingkat lanjut. AtomicReferenceArray mendukung operasi atom pada variabel array referensi yang mendasarinya. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Metode atomic CompareAndSet juga memiliki fitur konsistensi memori ini.
Metode AtomicReferenceArray
Berikut adalah daftar metode penting yang tersedia di kelas AtomicReferenceArray.
Sr.No. | Metode & Deskripsi |
---|---|
1 | public boolean compareAndSet(int i, E expect, E update) Secara atomis menyetel elemen di posisi i ke nilai yang diperbarui jika nilai saat ini == nilai yang diharapkan. |
2 | public E get(int i) Mendapat nilai saat ini pada posisi i. |
3 | public E getAndSet(int i, E newValue) Secara atomis menyetel elemen di posisi i ke nilai yang diberikan dan mengembalikan nilai lama. |
4 | public void lazySet(int i, E newValue) Akhirnya menetapkan elemen di posisi i ke nilai yang diberikan. |
5 | public int length() Mengembalikan panjang larik. |
6 | public void set(int i, E newValue) Setel elemen di posisi i ke nilai yang diberikan. |
7 | public String toString() Mengembalikan representasi String dari nilai-nilai array saat ini. |
8 | public boolean weakCompareAndSet(int i, E expect, E update) Secara atomis menyetel elemen di posisi i ke nilai yang diperbarui jika nilai saat ini == nilai yang diharapkan. |
Contoh
Program TestThread berikut menunjukkan penggunaan variabel AtomicReferenceArray di lingkungan berbasis thread.
import java.util.concurrent.atomic.AtomicReferenceArray;
public class TestThread {
private static String[] source = new String[10];
private static AtomicReferenceArray<String> atomicReferenceArray
= new AtomicReferenceArray<String>(source);
public static void main(final String[] arguments) throws InterruptedException {
for (int i = 0; i<atomicReferenceArray.length(); i++) {
atomicReferenceArray.set(i, "item-2");
}
Thread t1 = new Thread(new Increment());
Thread t2 = new Thread(new Compare());
t1.start();
t2.start();
t1.join();
t2.join();
}
static class Increment implements Runnable {
public void run() {
for(int i = 0; i<atomicReferenceArray.length(); i++) {
String add = atomicReferenceArray.getAndSet(i,"item-"+ (i+1));
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", value: "+ add);
}
}
}
static class Compare implements Runnable {
public void run() {
for(int i = 0; i<atomicReferenceArray.length(); i++) {
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", value: "+ atomicReferenceArray.get(i));
boolean swapped = atomicReferenceArray.compareAndSet(i, "item-2", "updated-item-2");
System.out.println("Item swapped: " + swapped);
if(swapped) {
System.out.println("Thread " + Thread.currentThread().getId()
+ ", index " +i + ", updated-item-2");
}
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Thread 9, index 0, value: item-2
Thread 10, index 0, value: item-1
Item swapped: false
Thread 10, index 1, value: item-2
Item swapped: true
Thread 9, index 1, value: updated-item-2
Thread 10, index 1, updated-item-2
Thread 10, index 2, value: item-3
Item swapped: false
Thread 10, index 3, value: item-2
Item swapped: true
Thread 10, index 3, updated-item-2
Thread 10, index 4, value: item-2
Item swapped: true
Thread 10, index 4, updated-item-2
Thread 10, index 5, value: item-2
Item swapped: true
Thread 10, index 5, updated-item-2
Thread 10, index 6, value: item-2
Thread 9, index 2, value: item-2
Item swapped: true
Thread 9, index 3, value: updated-item-2
Thread 10, index 6, updated-item-2
Thread 10, index 7, value: item-2
Thread 9, index 4, value: updated-item-2
Item swapped: true
Thread 9, index 5, value: updated-item-2
Thread 10, index 7, updated-item-2
Thread 9, index 6, value: updated-item-2
Thread 10, index 8, value: item-2
Thread 9, index 7, value: updated-item-2
Item swapped: true
Thread 9, index 8, value: updated-item-2
Thread 10, index 8, updated-item-2
Thread 9, index 9, value: item-2
Thread 10, index 9, value: item-10
Item swapped: false
Antarmuka java.util.concurrent.Executor adalah antarmuka sederhana untuk mendukung peluncuran tugas baru.
Metode ExecutorService
Sr.No. | Metode & Deskripsi |
---|---|
1 | void execute(Runnable command) Jalankan perintah yang diberikan di masa mendatang. |
Contoh
Program TestThread berikut menunjukkan penggunaan antarmuka Pelaksana di lingkungan berbasis utas.
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
Executor executor = Executors.newCachedThreadPool();
executor.execute(new Task());
ThreadPoolExecutor pool = (ThreadPoolExecutor)executor;
pool.shutdown();
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 5);
System.out.println("Running Task!");
TimeUnit.SECONDS.sleep(duration);
System.out.println("Task Completed");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Running Task!
Task Completed
Sebuah antarmuka java.util.concurrent.ExecutorService adalah subinterface dari antarmuka Executor, dan menambahkan fitur untuk mengelola siklus hidup, baik tugas individu dan pelaksana itu sendiri.
Metode ExecutorService
Sr.No. | Metode & Deskripsi |
---|---|
1 | boolean awaitTermination(long timeout, TimeUnit unit) Memblokir hingga semua tugas telah menyelesaikan eksekusi setelah permintaan penghentian, atau terjadi waktu tunggu, atau utas saat ini terputus, mana saja yang terjadi lebih dulu. |
2 | <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) Melaksanakan tugas yang diberikan, mengembalikan daftar Futures yang memegang status dan hasil mereka ketika semua selesai. |
3 | <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) Melaksanakan tugas yang diberikan, mengembalikan daftar Futures yang memegang status dan hasilnya ketika semua selesai atau batas waktu berakhir, mana saja yang terjadi lebih dulu. |
4 | <T> T invokeAny(Collection<? extends Callable<T>> tasks) Menjalankan tugas yang diberikan, mengembalikan hasil dari tugas yang telah diselesaikan dengan sukses (yaitu, tanpa mengeluarkan pengecualian), jika ada. |
5 | <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) Menjalankan tugas yang diberikan, mengembalikan hasil yang telah diselesaikan dengan sukses (yaitu, tanpa mengeluarkan pengecualian), jika ada yang dilakukan sebelum waktu tunggu yang diberikan berlalu. |
6 | boolean isShutdown() Mengembalikan nilai true jika pelaksana ini telah ditutup. |
7 | boolean isTerminated() Mengembalikan nilai benar jika semua tugas telah diselesaikan setelah dimatikan. |
8 | void shutdown() Memulai penghentian secara tertib di mana tugas yang dikirimkan sebelumnya dijalankan, tetapi tidak ada tugas baru yang akan diterima. |
9 | List<Runnable> shutdownNow() Mencoba menghentikan semua tugas yang sedang dijalankan secara aktif, menghentikan pemrosesan tugas menunggu, dan mengembalikan daftar tugas yang sedang menunggu eksekusi. |
10 | <T> Future<T> submit(Callable<T> task) Mengirimkan tugas yang menghasilkan nilai untuk dieksekusi dan mengembalikan Future yang mewakili hasil tugas yang tertunda. |
11 | Future<?> submit(Runnable task) Mengirimkan tugas Runnable untuk dieksekusi dan mengembalikan Future yang mewakili tugas itu. |
12 | <T> Future<T> submit(Runnable task, T result) Mengirimkan tugas Runnable untuk dieksekusi dan mengembalikan Future yang mewakili tugas itu. |
Contoh
Program TestThread berikut menunjukkan penggunaan antarmuka ExecutorService di lingkungan berbasis thread.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Task());
System.out.println("Shutdown executor");
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.err.println("tasks interrupted");
} finally {
if (!executor.isTerminated()) {
System.err.println("cancel non-finished tasks");
}
executor.shutdownNow();
System.out.println("shutdown finished");
}
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 20);
System.out.println("Running Task!");
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:302)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
at TestThread$Task.run(TestThread.java:39)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
Antarmuka java.util.concurrent.ScheduledExecutorService adalah subinterface dari antarmuka ExecutorService, dan mendukung pelaksanaan tugas di masa mendatang dan / atau berkala.
Metode ScheduledExecutorService
Sr.No. | Metode & Deskripsi |
---|---|
1 | <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) Membuat dan menjalankan ScheduledFuture yang menjadi aktif setelah penundaan tertentu. |
2 | ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) Membuat dan menjalankan aksi satu jepretan yang menjadi aktif setelah penundaan tertentu. |
3 | ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) Membuat dan menjalankan tindakan periodik yang menjadi aktif pertama setelah penundaan awal yang diberikan, dan selanjutnya dengan periode tertentu; Artinya, eksekusi akan dimulai setelah initialDelay lalu initialDelay + periode, lalu initialDelay + 2 * periode, dan seterusnya. |
4 | ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) Membuat dan menjalankan tindakan periodik yang menjadi diaktifkan terlebih dahulu setelah penundaan awal tertentu, dan kemudian dengan penundaan yang diberikan antara penghentian satu eksekusi dan dimulainya eksekusi berikutnya. |
Contoh
Program TestThread berikut menunjukkan penggunaan antarmuka ScheduledExecutorService di lingkungan berbasis thread.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> beepHandler =
scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beepHandler.cancel(true);
scheduler.shutdown();
}
}, 10, TimeUnit.SECONDS);
}
static class BeepTask implements Runnable {
public void run() {
System.out.println("beep");
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
beep
beep
beep
beep
Kumpulan thread tetap bisa didapatkan dengan memanggil metode newFixedThreadPool () statis kelas Executors.
Sintaksis
ExecutorService fixedPool = Executors.newFixedThreadPool(2);
dimana
Maksimum 2 utas akan aktif untuk memproses tugas.
Jika lebih dari 2 utas dikirim, maka mereka akan ditahan dalam antrian sampai utas tersedia.
Sebuah utas baru dibuat untuk menggantikannya jika utas dihentikan karena kegagalan selama penutupan eksekusi pada pelaksana belum dipanggil.
Setiap utas ada sampai kolam dimatikan.
Contoh
Program TestThread berikut menunjukkan penggunaan metode newFixedThreadPool di lingkungan berbasis thread.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);
// Cast the object to its class type
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
//Stats before tasks execution
System.out.println("Largest executions: "
+ pool.getLargestPoolSize());
System.out.println("Maximum allowed threads: "
+ pool.getMaximumPoolSize());
System.out.println("Current threads in pool: "
+ pool.getPoolSize());
System.out.println("Currently executing threads: "
+ pool.getActiveCount());
System.out.println("Total number of threads(ever scheduled): "
+ pool.getTaskCount());
executor.submit(new Task());
executor.submit(new Task());
//Stats after tasks execution
System.out.println("Core threads: " + pool.getCorePoolSize());
System.out.println("Largest executions: "
+ pool.getLargestPoolSize());
System.out.println("Maximum allowed threads: "
+ pool.getMaximumPoolSize());
System.out.println("Current threads in pool: "
+ pool.getPoolSize());
System.out.println("Currently executing threads: "
+ pool.getActiveCount());
System.out.println("Total number of threads(ever scheduled): "
+ pool.getTaskCount());
executor.shutdown();
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 5);
System.out.println("Running Task! Thread Name: " +
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(duration);
System.out.println("Task Completed! Thread Name: " +
Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Largest executions: 0
Maximum allowed threads: 2
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 2
Largest executions: 2
Maximum allowed threads: 2
Current threads in pool: 2
Currently executing threads: 1
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1
Kumpulan thread yang di-cache dapat diperoleh dengan memanggil metode newCachedThreadPool () statis kelas Executors.
Sintaksis
ExecutorService executor = Executors.newCachedThreadPool();
dimana
metode newCachedThreadPool membuat eksekutor yang memiliki kumpulan utas yang dapat diperluas.
Eksekutor seperti itu cocok untuk aplikasi yang meluncurkan banyak tugas berumur pendek.
Contoh
Program TestThread berikut menunjukkan penggunaan metode newCachedThreadPool di lingkungan berbasis utas.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
// Cast the object to its class type
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
//Stats before tasks execution
System.out.println("Largest executions: "
+ pool.getLargestPoolSize());
System.out.println("Maximum allowed threads: "
+ pool.getMaximumPoolSize());
System.out.println("Current threads in pool: "
+ pool.getPoolSize());
System.out.println("Currently executing threads: "
+ pool.getActiveCount());
System.out.println("Total number of threads(ever scheduled): "
+ pool.getTaskCount());
executor.submit(new Task());
executor.submit(new Task());
//Stats after tasks execution
System.out.println("Core threads: " + pool.getCorePoolSize());
System.out.println("Largest executions: "
+ pool.getLargestPoolSize());
System.out.println("Maximum allowed threads: "
+ pool.getMaximumPoolSize());
System.out.println("Current threads in pool: "
+ pool.getPoolSize());
System.out.println("Currently executing threads: "
+ pool.getActiveCount());
System.out.println("Total number of threads(ever scheduled): "
+ pool.getTaskCount());
executor.shutdown();
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 5);
System.out.println("Running Task! Thread Name: " +
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(duration);
System.out.println("Task Completed! Thread Name: " +
Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 2
Maximum allowed threads: 2147483647
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1
Kumpulan thread terjadwal dapat diperoleh dengan memanggil metode newScheduledThreadPool () statis kelas Executors.
Sintaksis
ExecutorService executor = Executors.newScheduledThreadPool(1);
Contoh
Program TestThread berikut menunjukkan penggunaan metode newScheduledThreadPool di lingkungan berbasis thread.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> beepHandler =
scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beepHandler.cancel(true);
scheduler.shutdown();
}
}, 10, TimeUnit.SECONDS);
}
static class BeepTask implements Runnable {
public void run() {
System.out.println("beep");
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
beep
beep
beep
beep
Kumpulan thread tunggal bisa didapatkan dengan memanggil metode newSingleThreadExecutor () statis kelas Executors.
Sintaksis
ExecutorService executor = Executors.newSingleThreadExecutor();
Di mana metode newSingleThreadExecutor membuat eksekutor yang mengeksekusi satu tugas dalam satu waktu.
Contoh
Program TestThread berikut menunjukkan penggunaan metode newSingleThreadExecutor di lingkungan berbasis thread.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Task());
System.out.println("Shutdown executor");
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.err.println("tasks interrupted");
} finally {
if (!executor.isTerminated()) {
System.err.println("cancel non-finished tasks");
}
executor.shutdownNow();
System.out.println("shutdown finished");
}
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 20);
System.out.println("Running Task!");
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:302)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
at TestThread$Task.run(TestThread.java:39) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
java.util.concurrent.ThreadPoolExecutor adalah ExecutorService untuk menjalankan setiap tugas yang dikirimkan menggunakan salah satu dari beberapa kumpulan thread, biasanya dikonfigurasi menggunakan metode pabrik Executors. Ini juga menyediakan berbagai metode utilitas untuk memeriksa statistik utas saat ini dan mengontrolnya.
Metode ThreadPoolExecutor
Sr.No. | Metode & Deskripsi |
---|---|
1 | protected void afterExecute(Runnable r, Throwable t) Metode dipanggil setelah menyelesaikan eksekusi Runnable yang diberikan. |
2 | void allowCoreThreadTimeOut(boolean value) Menyetel kebijakan yang mengatur apakah utas inti dapat waktu habis dan dihentikan jika tidak ada tugas yang tiba dalam waktu keep-hidup, diganti jika diperlukan saat tugas baru tiba. |
3 | boolean allowsCoreThreadTimeOut() Mengembalikan nilai true jika kumpulan ini memungkinkan utas inti untuk waktu habis dan diakhiri jika tidak ada tugas yang tiba dalam waktu keepAlive, diganti jika diperlukan ketika tugas baru tiba. |
4 | boolean awaitTermination(long timeout, TimeUnit unit) Memblokir hingga semua tugas telah menyelesaikan eksekusi setelah permintaan penghentian, atau terjadi waktu tunggu, atau utas saat ini terputus, mana saja yang terjadi lebih dulu. |
5 | protected void beforeExecute(Thread t, Runnable r) Metode dipanggil sebelum menjalankan Runnable yang diberikan di thread yang diberikan. |
6 | void execute(Runnable command) Menjalankan tugas yang diberikan suatu saat nanti. |
7 | protected void finalize() Memanggil shutdown ketika pelaksana ini tidak lagi direferensikan dan tidak memiliki utas. |
8 | int getActiveCount() Mengembalikan perkiraan jumlah utas yang secara aktif menjalankan tugas. |
9 | long getCompletedTaskCount() Mengembalikan perkiraan jumlah tugas yang telah menyelesaikan eksekusi. |
10 | int getCorePoolSize() Mengembalikan jumlah inti utas. |
11 | long getKeepAliveTime(TimeUnit unit) Mengembalikan waktu tetap hidup utas, yang merupakan jumlah waktu utas yang melebihi ukuran kumpulan inti dapat tetap menganggur sebelum dihentikan. |
12 | int getLargestPoolSize() Menampilkan jumlah utas terbesar yang pernah ada di kumpulan secara bersamaan. |
13 | int getMaximumPoolSize() Menampilkan jumlah utas maksimum yang diizinkan. |
14 | int getPoolSize() Mengembalikan jumlah utas saat ini di pangkalan. |
15 | BlockingQueue
Mengembalikan antrian tugas yang digunakan oleh pelaksana ini. |
15 | RejectedExecutionHandler getRejectedExecutionHandler() Mengembalikan penangan saat ini untuk tugas yang tidak bisa dijalankan. |
16 | long getTaskCount() Mengembalikan perkiraan jumlah total tugas yang pernah dijadwalkan untuk dieksekusi. |
17 | ThreadFactory getThreadFactory() Mengembalikan pabrik utas yang digunakan untuk membuat utas baru. |
18 | boolean isShutdown() Mengembalikan nilai true jika pelaksana ini telah ditutup. |
19 | boolean isTerminated() Mengembalikan nilai benar jika semua tugas telah diselesaikan setelah dimatikan. |
20 | boolean isTerminating() Mengembalikan nilai true jika eksekutor ini sedang dalam proses penghentian setelah shutdown () atau shutdownNow () tetapi belum sepenuhnya dihentikan. |
21 | int prestartAllCoreThreads() Memulai semua utas inti, menyebabkan utas menunggu pekerjaan. |
22 | boolean prestartCoreThread() Memulai utas inti, menyebabkan utas menunggu pekerjaan. |
23 | void purge() Mencoba menghapus semua tugas Masa Depan yang telah dibatalkan dari antrian pekerjaan. |
24 | boolean remove(Runnable task) Menghapus tugas ini dari antrian internal eksekutor jika ada, sehingga menyebabkannya tidak dijalankan jika belum dimulai. |
25 | void setCorePoolSize(int corePoolSize) Menetapkan jumlah inti utas. |
26 | void setKeepAliveTime(long time, TimeUnit unit) Menyetel batas waktu utas mungkin tetap menganggur sebelum dihentikan. |
27 | void setMaximumPoolSize(int maximumPoolSize) Menetapkan jumlah utas maksimum yang diizinkan. |
28 | void setRejectedExecutionHandler(RejectedExecutionHandler handler) Menyetel penangan baru untuk tugas yang tidak bisa dijalankan. |
29 | void setThreadFactory(ThreadFactory threadFactory) Mengatur pabrik utas yang digunakan untuk membuat utas baru. |
30 | void shutdown() Memulai penghentian secara tertib di mana tugas yang dikirimkan sebelumnya dijalankan, tetapi tidak ada tugas baru yang akan diterima. |
31 | List<Runnable> shutdownNow() Mencoba menghentikan semua tugas yang sedang dijalankan secara aktif, menghentikan pemrosesan tugas menunggu, dan mengembalikan daftar tugas yang sedang menunggu eksekusi. |
32 | protected void terminated() Metode dipanggil ketika Pelaksana telah dihentikan. |
33 | String toString() Mengembalikan string yang mengidentifikasi kumpulan ini, serta statusnya, termasuk indikasi status berjalan dan perkiraan jumlah pekerja dan tugas. |
Contoh
Program TestThread berikut menunjukkan penggunaan antarmuka ThreadPoolExecutor di lingkungan berbasis thread.
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
//Stats before tasks execution
System.out.println("Largest executions: "
+ executor.getLargestPoolSize());
System.out.println("Maximum allowed threads: "
+ executor.getMaximumPoolSize());
System.out.println("Current threads in pool: "
+ executor.getPoolSize());
System.out.println("Currently executing threads: "
+ executor.getActiveCount());
System.out.println("Total number of threads(ever scheduled): "
+ executor.getTaskCount());
executor.submit(new Task());
executor.submit(new Task());
//Stats after tasks execution
System.out.println("Core threads: " + executor.getCorePoolSize());
System.out.println("Largest executions: "
+ executor.getLargestPoolSize());
System.out.println("Maximum allowed threads: "
+ executor.getMaximumPoolSize());
System.out.println("Current threads in pool: "
+ executor.getPoolSize());
System.out.println("Currently executing threads: "
+ executor.getActiveCount());
System.out.println("Total number of threads(ever scheduled): "
+ executor.getTaskCount());
executor.shutdown();
}
static class Task implements Runnable {
public void run() {
try {
Long duration = (long) (Math.random() * 5);
System.out.println("Running Task! Thread Name: " +
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(duration);
System.out.println("Task Completed! Thread Name: " +
Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 2
Maximum allowed threads: 2147483647
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-2
Running Task! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-2
java.util.concurrent.ScheduledThreadPoolExecutor adalah subclass dari ThreadPoolExecutor dan juga dapat menjadwalkan perintah untuk dijalankan setelah penundaan tertentu, atau untuk dieksekusi secara berkala.
ScheduledThreadPoolExecutor Metode
Sr.No. | Metode & Deskripsi |
---|---|
1 | protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) Mengubah atau mengganti tugas yang digunakan untuk menjalankan callable. |
2 | protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) Mengubah atau mengganti tugas yang digunakan untuk menjalankan runnable. |
3 | void execute(Runnable command) Jalankan perintah tanpa penundaan yang diperlukan. |
4 | boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() Mendapatkan kebijakan tentang apakah akan terus menjalankan tugas periodik yang ada meskipun pelaksana ini telah dimatikan. |
5 | boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() Mendapatkan kebijakan tentang apakah akan menjalankan tugas tertunda yang ada meskipun pelaksana ini telah dimatikan. |
6 | BlockingQueue<Runnable> getQueue() Mengembalikan antrian tugas yang digunakan oleh pelaksana ini. |
7 | boolean getRemoveOnCancelPolicy() Mendapat kebijakan tentang apakah tugas yang dibatalkan harus segera dihapus dari antrian pekerjaan pada saat pembatalan. |
8 | <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) Membuat dan menjalankan ScheduledFuture yang menjadi aktif setelah penundaan tertentu. |
9 | ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) Membuat dan menjalankan aksi satu jepretan yang menjadi aktif setelah penundaan tertentu. |
10 | ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) Membuat dan menjalankan tindakan periodik yang menjadi aktif pertama setelah penundaan awal yang diberikan, dan selanjutnya dengan periode tertentu; Artinya, eksekusi akan dimulai setelah initialDelay lalu initialDelay + periode, lalu initialDelay + 2 * periode, dan seterusnya. |
11 | ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) Membuat dan menjalankan tindakan periodik yang menjadi diaktifkan terlebih dahulu setelah penundaan awal tertentu, dan kemudian dengan penundaan yang diberikan antara penghentian satu eksekusi dan dimulainya eksekusi berikutnya. |
12 | void setContinueExistingPeriodicTasksAfterShutdownPolicy (boolean value) Menyetel kebijakan tentang apakah akan terus menjalankan tugas periodik yang ada meskipun pelaksana ini telah dimatikan. |
13 | void setExecuteExistingDelayedTasksAfterShutdownPolicy (boolean value) Menyetel kebijakan tentang apakah akan menjalankan tugas tertunda yang ada meskipun pelaksana ini telah dimatikan. |
14 | void setRemoveOnCancelPolicy(boolean value) Menyetel kebijakan tentang apakah tugas yang dibatalkan harus segera dihapus dari antrian pekerjaan pada saat pembatalan. |
15 | void shutdown() Memulai penghentian secara tertib di mana tugas yang dikirimkan sebelumnya dijalankan, tetapi tidak ada tugas baru yang akan diterima. |
16 | List<Runnable> shutdownNow() Mencoba menghentikan semua tugas yang sedang dijalankan secara aktif, menghentikan pemrosesan tugas menunggu, dan mengembalikan daftar tugas yang sedang menunggu eksekusi. |
17 | <T> Future<T> submit(Callable<T> task) Mengirimkan tugas yang menghasilkan nilai untuk dieksekusi dan mengembalikan Future yang mewakili hasil tugas yang tertunda. |
18 | Future<?> submit(Runnable task) Mengirimkan tugas Runnable untuk dieksekusi dan mengembalikan Future yang mewakili tugas itu. |
19 | <T> Future<T> submit(Runnable task, T result) Mengirimkan tugas Runnable untuk dieksekusi dan mengembalikan Future yang mewakili tugas itu. |
Contoh
Program TestThread berikut menunjukkan penggunaan antarmuka ScheduledThreadPoolExecutor di lingkungan berbasis thread.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
final ScheduledThreadPoolExecutor scheduler =
(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);
final ScheduledFuture<?> beepHandler =
scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);
scheduler.schedule(new Runnable() {
@Override
public void run() {
beepHandler.cancel(true);
scheduler.shutdown();
}
}, 10, TimeUnit.SECONDS);
}
static class BeepTask implements Runnable {
public void run() {
System.out.println("beep");
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
beep
beep
beep
beep
Objek java.util.concurrent.Callable dapat mengembalikan hasil komputasi yang dilakukan oleh thread berbeda dengan antarmuka runnable yang hanya dapat menjalankan thread. Objek Callable mengembalikan objek Future yang menyediakan metode untuk memantau kemajuan tugas yang sedang dijalankan oleh utas. Objek Future dapat digunakan untuk memeriksa status Callable dan kemudian mengambil hasil dari Callable setelah thread selesai. Ini juga menyediakan fungsionalitas batas waktu.
Sintaksis
//submit the callable using ThreadExecutor
//and get the result as a Future object
Future<Long> result10 = executor.submit(new FactorialService(10));
//get the result using get method of the Future object
//get method waits till the thread execution and then return the result of the execution.
Long factorial10 = result10.get();
Contoh
Program TestThread berikut menunjukkan penggunaan Futures dan Callables di lingkungan berbasis thread.
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException,
ExecutionException {
ExecutorService executor = Executors.newSingleThreadExecutor();
System.out.println("Factorial Service called for 10!");
Future<Long> result10 = executor.submit(new FactorialService(10));
System.out.println("Factorial Service called for 20!");
Future<Long> result20 = executor.submit(new FactorialService(20));
Long factorial10 = result10.get();
System.out.println("10! = " + factorial10);
Long factorial20 = result20.get();
System.out.println("20! = " + factorial20);
executor.shutdown();
}
static class FactorialService implements Callable<Long> {
private int number;
public FactorialService(int number) {
this.number = number;
}
@Override
public Long call() throws Exception {
return factorial();
}
private Long factorial() throws InterruptedException {
long result = 1;
while (number != 0) {
result = number * result;
number--;
Thread.sleep(100);
}
return result;
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Factorial Service called for 10!
Factorial Service called for 20!
10! = 3628800
20! = 2432902008176640000
Kerangka kerja fork-join memungkinkan untuk menghentikan tugas tertentu pada beberapa pekerja dan kemudian menunggu hasil untuk menggabungkannya. Ini memanfaatkan kapasitas mesin multi-prosesor secara luas. Berikut adalah konsep dan objek inti yang digunakan dalam kerangka kerja fork-join.
Garpu
Fork adalah proses di mana tugas membagi dirinya menjadi sub-tugas yang lebih kecil dan independen yang dapat dijalankan secara bersamaan.
Sintaksis
Sum left = new Sum(array, low, mid);
left.fork();
Berikut Sum adalah subclass dari RecursiveTask dan left.fork () membagi tugas menjadi sub-tugas.
Ikuti
Bergabung adalah proses di mana tugas menggabungkan semua hasil sub-tugas setelah subtugas selesai dijalankan, jika tidak maka terus menunggu.
Sintaksis
left.join();
Di kiri sini adalah objek kelas Sum.
ForkJoinPool
ini adalah kumpulan utas khusus yang dirancang untuk bekerja dengan pemisahan tugas fork-and-join.
Sintaksis
ForkJoinPool forkJoinPool = new ForkJoinPool(4);
Di sini ForkJoinPool baru dengan tingkat paralelisme 4 CPU.
RecursiveAction
RecursiveAction mewakili tugas yang tidak mengembalikan nilai apa pun.
Sintaksis
class Writer extends RecursiveAction {
@Override
protected void compute() { }
}
RecursiveTask
RecursiveTask mewakili tugas yang mengembalikan nilai.
Sintaksis
class Sum extends RecursiveTask<Long> {
@Override
protected Long compute() { return null; }
}
Contoh
Program TestThread berikut menunjukkan penggunaan kerangka kerja Fork-Join di lingkungan berbasis thread.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException,
ExecutionException {
int nThreads = Runtime.getRuntime().availableProcessors();
System.out.println(nThreads);
int[] numbers = new int[1000];
for(int i = 0; i < numbers.length; i++) {
numbers[i] = i;
}
ForkJoinPool forkJoinPool = new ForkJoinPool(nThreads);
Long result = forkJoinPool.invoke(new Sum(numbers,0,numbers.length));
System.out.println(result);
}
static class Sum extends RecursiveTask<Long> {
int low;
int high;
int[] array;
Sum(int[] array, int low, int high) {
this.array = array;
this.low = low;
this.high = high;
}
protected Long compute() {
if(high - low <= 10) {
long sum = 0;
for(int i = low; i < high; ++i)
sum += array[i];
return sum;
} else {
int mid = low + (high - low) / 2;
Sum left = new Sum(array, low, mid);
Sum right = new Sum(array, mid, high);
left.fork();
long rightResult = right.compute();
long leftResult = left.join();
return leftResult + rightResult;
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
32
499500
Antarmuka java.util.concurrent.BlockingQueue adalah subinterface Antarmuka Antrean, dan juga mendukung operasi seperti menunggu antrean menjadi tidak kosong sebelum mengambil elemen, dan menunggu ruang tersedia dalam antrean sebelum menyimpan elemen .
Metode BlockingQueue
Sr.No. | Metode & Deskripsi |
---|---|
1 | boolean add(E e) Menyisipkan elemen yang ditentukan ke dalam antrean ini jika memungkinkan untuk dilakukan segera tanpa melanggar batasan kapasitas, mengembalikan nilai true setelah berhasil dan menampilkan IllegalStateException jika tidak ada ruang yang tersedia saat ini. |
2 | boolean contains(Object o) Mengembalikan nilai true jika antrian ini berisi elemen yang ditentukan. |
3 | int drainTo(Collection<? super E> c) Menghapus semua elemen yang tersedia dari antrian ini dan menambahkannya ke koleksi yang diberikan. |
4 | int drainTo(Collection<? super E> c, int maxElements) Menghapus maksimal sejumlah elemen yang tersedia dari antrean ini dan menambahkannya ke koleksi yang diberikan. |
5 | boolean offer(E e) Menyisipkan elemen yang ditentukan ke dalam antrian ini jika memungkinkan untuk melakukannya segera tanpa melanggar batasan kapasitas, mengembalikan nilai true setelah berhasil dan false jika tidak ada ruang yang tersedia saat ini. |
6 | boolean offer(E e, long timeout, TimeUnit unit) Menyisipkan elemen yang ditentukan ke dalam antrian ini, menunggu hingga waktu tunggu yang ditentukan jika perlu agar ruang tersedia. |
7 | E poll(long timeout, TimeUnit unit) Mengambil dan menghapus kepala antrean ini, menunggu hingga waktu tunggu yang ditentukan jika perlu agar elemen tersedia. |
8 | void put(E e) Menyisipkan elemen yang ditentukan ke dalam antrian ini, menunggu jika perlu sampai ruang tersedia. |
9 | int remainingCapacity() Mengembalikan jumlah elemen tambahan yang idealnya dapat diterima antrean ini (jika tidak ada batasan memori atau sumber daya) tanpa pemblokiran, atau Integer.MAX_VALUE jika tidak ada batas intrinsik. |
10 | boolean remove(Object o) Menghapus satu instance dari elemen yang ditentukan dari antrian ini, jika ada. |
11 | E take() Mengambil dan menghapus kepala antrean ini, menunggu jika perlu hingga elemen tersedia. |
Contoh
Program TestThread berikut menunjukkan penggunaan antarmuka BlockingQueue di lingkungan berbasis thread.
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class TestThread {
public static void main(final String[] arguments) throws InterruptedException {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
new Thread(producer).start();
new Thread(consumer).start();
Thread.sleep(4000);
}
static class Producer implements Runnable {
private BlockingQueue<Integer> queue;
public Producer(BlockingQueue queue) {
this.queue = queue;
}
@Override
public void run() {
Random random = new Random();
try {
int result = random.nextInt(100);
Thread.sleep(1000);
queue.put(result);
System.out.println("Added: " + result);
result = random.nextInt(100);
Thread.sleep(1000);
queue.put(result);
System.out.println("Added: " + result);
result = random.nextInt(100);
Thread.sleep(1000);
queue.put(result);
System.out.println("Added: " + result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
private BlockingQueue<Integer> queue;
public Consumer(BlockingQueue queue) {
this.queue = queue;
}
@Override
public void run() {
try {
System.out.println("Removed: " + queue.take());
System.out.println("Removed: " + queue.take());
System.out.println("Removed: " + queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Added: 52
Removed: 52
Added: 70
Removed: 70
Added: 27
Removed: 27
Antarmuka java.util.concurrent.ConcurrentMap adalah subinterface antarmuka Map, mendukung operasi atom pada variabel peta yang mendasarinya. Itu telah mendapatkan dan menetapkan metode yang berfungsi seperti membaca dan menulis pada variabel volatil. Artinya, himpunan memiliki hubungan terjadi-sebelum dengan get berikutnya pada variabel yang sama. Antarmuka ini memastikan keamanan benang dan jaminan atomicity.
Metode ConcurrentMap
Sr.No. | Metode & Deskripsi |
---|---|
1 | default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) Mencoba menghitung pemetaan untuk kunci yang ditentukan dan nilai yang dipetakan saat ini (atau null jika tidak ada pemetaan saat ini). |
2 | default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) Jika kunci yang ditentukan belum dikaitkan dengan sebuah nilai (atau dipetakan ke nol), mencoba untuk menghitung nilainya menggunakan fungsi pemetaan yang diberikan dan memasukkannya ke dalam peta ini kecuali null. |
3 | default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) Jika nilai untuk kunci yang ditentukan ada dan bukan nol, mencoba untuk menghitung pemetaan baru dengan kunci tersebut dan nilai yang dipetakan saat ini. |
4 | default void forEach(BiConsumer<? super K,? super V> action) Melakukan tindakan yang diberikan untuk setiap entri di peta ini sampai semua entri telah diproses atau tindakan tersebut mengeluarkan pengecualian. |
5 | default V getOrDefault(Object key, V defaultValue) Menampilkan nilai yang dipetakan untuk kunci yang ditentukan, atau defaultValue jika peta ini tidak berisi pemetaan untuk kunci tersebut. |
6 | default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction) Jika kunci yang ditentukan belum dikaitkan dengan nilai atau dikaitkan dengan null, kaitkan dengan nilai bukan null yang diberikan. |
7 | V putIfAbsent(K key, V value) Jika kunci yang ditentukan belum dikaitkan dengan nilai, kaitkan dengan nilai yang diberikan. |
8 | boolean remove(Object key, Object value) Menghapus entri untuk kunci hanya jika saat ini dipetakan ke nilai tertentu. |
9 | V replace(K key, V value) Mengganti entri untuk kunci hanya jika saat ini dipetakan ke beberapa nilai. |
10 | boolean replace(K key, V oldValue, V newValue) Mengganti entri untuk kunci hanya jika saat ini dipetakan ke nilai tertentu. |
11 | default void replaceAll(BiFunction<? super K,? super V,? extends V> function) Mengganti nilai setiap entri dengan hasil pemanggilan fungsi yang diberikan pada entri itu sampai semua entri telah diproses atau fungsi tersebut mengeluarkan pengecualian. |
Contoh
Program TestThread berikut menunjukkan penggunaan ConcurrentMap vs HashMap.
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class TestThread {
public static void main(final String[] arguments) {
Map<String,String> map = new ConcurrentHashMap<String, String>();
map.put("1", "One");
map.put("2", "Two");
map.put("3", "Three");
map.put("5", "Five");
map.put("6", "Six");
System.out.println("Initial ConcurrentHashMap: " + map);
Iterator<String> iterator = map.keySet().iterator();
try {
while(iterator.hasNext()) {
String key = iterator.next();
if(key.equals("3")) {
map.put("4", "Four");
}
}
} catch(ConcurrentModificationException cme) {
cme.printStackTrace();
}
System.out.println("ConcurrentHashMap after modification: " + map);
map = new HashMap<String, String>();
map.put("1", "One");
map.put("2", "Two");
map.put("3", "Three");
map.put("5", "Five");
map.put("6", "Six");
System.out.println("Initial HashMap: " + map);
iterator = map.keySet().iterator();
try {
while(iterator.hasNext()) {
String key = iterator.next();
if(key.equals("3")) {
map.put("4", "Four");
}
}
System.out.println("HashMap after modification: " + map);
} catch(ConcurrentModificationException cme) {
cme.printStackTrace();
}
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Initial ConcurrentHashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
ConcurrentHashMap after modification: {1 = One, 2 = Two, 3 = Three, 4 = Four, 5 = Five, 6 = Six}
Initial HashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at TestThread.main(TestThread.java:48)
Antarmuka java.util.concurrent.ConcurrentNavigableMap adalah subinterface dari antarmuka ConcurrentMap, dan mendukung operasi NavigableMap, dan secara rekursif untuk sub-peta yang dapat dinavigasi, dan perkiraan kecocokan.
Metode ConcurrentMap
Sr.No. | Metode & Deskripsi |
---|---|
1 | NavigableSet<K> descendingKeySet() Mengembalikan tampilan NavigableSet urutan terbalik dari kunci yang terdapat dalam peta ini. |
2 | ConcurrentNavigableMap<K,V> descendingMap() Mengembalikan tampilan urutan terbalik dari pemetaan yang ada di peta ini. |
3 | ConcurrentNavigableMap<K,V> headMap(K toKey) Mengembalikan tampilan dari bagian peta ini yang kuncinya lebih kecil dari toKey. |
4 | ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive) Mengembalikan tampilan dari bagian peta ini yang kuncinya kurang dari (atau sama dengan, jika inklusif benar) toKey. |
5 | NavigableSet<K> keySet() Mengembalikan tampilan NavigableSet dari kunci yang ada di peta ini. |
6 | NavigableSet<K> navigableKeySet() Mengembalikan tampilan NavigableSet dari kunci yang ada di peta ini. |
7 | ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) Mengembalikan tampilan dari bagian peta ini yang kuncinya berkisar dari fromKey ke toKey. |
8 | ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) Mengembalikan tampilan dari bagian peta ini yang kuncinya berkisar dari fromKey, inklusif, hingga toKey, eksklusif. |
9 | ConcurrentNavigableMap<K,V> tailMap(K fromKey) Mengembalikan tampilan dari bagian peta ini yang kuncinya lebih besar dari atau sama dengan fromKey. |
10 | ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive) Mengembalikan tampilan dari bagian peta ini yang kuncinya lebih besar dari (atau sama dengan, jika inklusif benar) fromKey. |
Contoh
Program TestThread berikut menunjukkan penggunaan ConcurrentNavigableMap.
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
public class TestThread {
public static void main(final String[] arguments) {
ConcurrentNavigableMap<String,String> map =
new ConcurrentSkipListMap<String, String>();
map.put("1", "One");
map.put("2", "Two");
map.put("3", "Three");
map.put("5", "Five");
map.put("6", "Six");
System.out.println("Initial ConcurrentHashMap: "+map);
System.out.println("HeadMap(\"2\") of ConcurrentHashMap: "+map.headMap("2"));
System.out.println("TailMap(\"2\") of ConcurrentHashMap: "+map.tailMap("2"));
System.out.println(
"SubMap(\"2\", \"4\") of ConcurrentHashMap: "+map.subMap("2","4"));
}
}
Ini akan menghasilkan hasil sebagai berikut.
Keluaran
Initial ConcurrentHashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
HeadMap("2") of ConcurrentHashMap: {1 = One}
TailMap("2") of ConcurrentHashMap: {2 = Two, 3 = Three, 5 = Five, 6 = Six}
SubMap("2", "4") of ConcurrentHashMap: {2 = Two, 3 = Three}