Multithreading mengacu kepada dua atau lebih task
(tugas, thread) yang berjalan (sedang dieksekusi) di dalam satu program. Thread
merupakan suatu path eksekusi independen di dalam program. Banyak thread dapat
nerjalan secara konkuren (berbarengan) di dalam program. Setiap thread di dalam
Java dibuat dan dikendalikan oleh kelas java.lang.Thread. Suatu program Java
dapat mempunyai banyak thread, dan thread-thread ini dapat berjalan secara
bersamaan, secara asinkron atau sinkron.
Multithreading mempunyai beberapa keuntungan,
dibandingkan multiprocessing, di antaranya:
- Thread
bersifat lightweight, sedangkan proses lebih berat. Perlu diketahui bahwa
proses adalah program yang sedang berada di memory atau processor, sedang
dieksekusi. Thread dapat diartikan sebagai anak dari proses.
- Thread-thread
berbagi pakai ruang alamat yang sama dan karena itu dapat berbagi pakai
data dan kode (instruksi)
- Context
switching antar thread biasanya lebih murah daripada antar proses.
- Biaya
komunikasi antar thread relatif lebih rendah daripada komunikasi antar
proses.
- Thread
memungkinkan task-task berbeda dikerjakan secara konkuren.
Note: Penjelasan
lebih detail mengenai konsep thread dan proses dapat dibaca pada buku teks
mengenai Sistem Operasi, di antaranya karya Stallings dan Tanenbaum yang banyak
digunakan di Universitas di Dunia.
Kelas Thread merupakan turunan dari kelas Object.
Kelas Object sendiri mempunyai metode notify(), notifyAll() dan wait(),
sedangkan kelas Thread menyediakan metode sleep() dan yield(). Metode-metode
ini akan sering digunakan dalam pengelolaan aplikasi banyak thread.
Pembuatan Thread
Terdapat 2 (dua) cara membuat thread di dalam
Java:
- Mengimplementasikan
interface Runnable (java.lang.Runnable)
- Menurunkan
(extend) kelas Thread (java.lang.Thread)
Mengimplementasikan Interface Runnable
Bentuk dasar (signature) dari interface Runnable
adalah
1
2
3
|
public interface Runnable {
void run();
}
|
Pada pendekatan ini, kita harus membuat sebuah
kelas yang implementasi interface Runnable menggunakan kata kunci implements
Runnable. Kemudian dibuat instansiasi berupa suatu obyek dari kelas itu.
Kita perlu meng-override metode run() di dalam kelas itu, satu-satunya
metode yang perlu diimplementasikan. Metode run() mengandung logika dari thread
yang dibangun.
Prosedur pembuatan thread berdasarkan pendekatan
interface Runnable adalah sebagai berikut:
- Sebuah
kelas meng-implements interface Runnable, menyediakan metode run() di
dalamnya yang akan dieksekusi oleh thread nantinya. Obyek dari kelas ini
merupakan obyek Runnable.
- Obyek
dari kelas Thread dibuat dengan melewatkan obyek Runnable sebagai argumen
ke konstruktur Thread. Obyek Thread sekarang mempunyai suatu obyek
Runnable yang mengimplementasikan metode run().
- Metode
start() pada obyek Thread yang dibuat sebelumnya dipanggil. Metode start()
tersebut kembali segera setelah suatu thread dilahirkan (berhasil dibuat).
- Thread
berakhir ketika metode run() berakhir, baik dengan penyelesaian normal
atau dengan melempar suatu eksepsi tidak tertangkap (uncaught exception).
Di bawah ini adalah sebuah program yang
mengilustrasikan pembuatan thread menggunakan interfaca Runnable, bukan
meng-extend kelas Thread. Suatu thread dimulai ketika kita memanggil metode
start() pada obyek yang dibuat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
class RunnableThread implements Runnable
{
Thread runner;
public RunnableThread()
{ }
public RunnableThread(String
threadName) {
runner
= new Thread(this, threadName); // (1) Buat thread baru.
System.out.println(runner.getName());
runner.start(); //
(2) Memulai eksekusi thread tersebut.
}
public void run()
{
//Tampilkan
info tentang thread ini
System.out.println(Thread.currentThread());
}
}
public class RunnableExample {
public static void main(String[]
args) {
Thread
thread1 = new Thread(new RunnableThread(), "thread1");
Thread
thread2 = new Thread(new RunnableThread(), "thread2");
RunnableThread
thread3 = new RunnableThread("thread3");
//Memulai
eksekusi thread.
thread1.start();
thread2.start();
try {
//delay
selama satu detik (1000 ms).
Thread.currentThread().sleep(1000);
} catch (InterruptedException
e) { }
//Tampilkan
info tentang thread main (utama).
System.out.println(Thread.currentThread());
}
}
|
Keluaran dari Program di atas dapat berupa:
thread3
Thread[thread1,5,main]
Thread[thread2,5,main]
Thread[thread3,5,main]
Thread[main,5,main]private
Thread[thread1,5,main]
Thread[thread2,5,main]
Thread[thread3,5,main]
Thread[main,5,main]private
Pendekatan ini harus digunakan jika kelas yang
menginstansiasi obyek thread diperlukan (sebagai parent) untuk membuat
kelas-kelas lain yang merupakan keturunannya. Pada kasus demikian, kita tidak
boleh menurunkan kelas Thread, harus mengimplementasikan Runnable.
Meng-Extend Kelas Thread
Prosedur pembuatan thread melalui pendekatan
penurunan kelas Thread adalah sebagai berikut:
- Membuat
sebuah sub-kelas turunan dari kelas Thread, kemudian meng-override metode
run() dari kelas Thread dan di dalamnya didefinisikan beberapa kode yang
dieksekusi oleh thread.
- Sub-kelas
ini dapat memanggil suatu konstruktur Thread secara eksplisit untuk
menginisialisasi thread, menggunakan metode super().
- Metode
start() yang telah diturunkan (secara otomatis) dari kelas Thread
dipanggil agar thread segera berjalan.
Berikut ini adalah sebuah program yang
mengilustrasikan pembuatan thread dengan meng-extend kelas Thread sebagai ganti
mengimplementasikan interface Runnable. Metode start() digunakanuntuk
mengeksekusi obyek thread yang dibuat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
class XThread extends Thread {
XThread() { }
XThread(String
threadName) {
super(threadName); //
Memulai thread.
System.out.println(this);
start();
}
public void run()
{
//Tampilkan
info tentang thread ini
System.out.println(Thread.currentThread().getName());
}
}
public class ThreadExample {
public static void main(String[]
args) {
Thread
thread1 = new Thread(new XThread(), "thread1");
Thread
thread2 = new Thread(new XThread(), "thread2");
//
2 thread diberikan nama default
Thread
thread3 = new XThread();
Thread
thread4 = new XThread();
Thread
thread5 = new XThread("thread5");
//Memulai
eksekusi thread
thread1.start();
thread2.start();
thread3.start();
thread4.start();
try {
//Metode sleep()
dipanggil pada thred main (utama), delay 1 detik.
Thread.currentThread().sleep(1000);
} catch (InterruptedException
e) { }
//Tampilkan
info tentang thread main
System.out.println(Thread.currentThread());
}
}
|
Keluaran yang diperoleh dapat berupa:
Thread[thread5,5,main]
thread1
thread5
thread2
Thread-3
Thread-2
Thread[main,5,main]
thread1
thread5
thread2
Thread-3
Thread-2
Thread[main,5,main]
Pada saat membuat thread, ada dua alasan mengapa
kita mengimplementasikan interface Runnable, bukan meng-extend kelas Thread:
- Menurunkan
kelas Thread berarti bahwa subclass tidak dapat diturunkan menjadi kelas
lain lagi, sedangkan suatu kelas yang mengimplementasikan interface
Runnable mempunyai opsi ini.
- Suatu
kelas mungkin hanya diinginkan runnable, karena itu menurunkan Thread
secara penuh merupakan pemborosan.
Contoh dari kelas anonim berikut memperlihatkan
bagaimana membuat sebuah thread dan langsung menjalankannya:
1
2
3
4
5
6
|
( new Thread() {
public void run() {
for(;;)
System.out.println(”Stop the world!”);
}
}
).start();
|