unisbadri.com » Python Java Golang Typescript Kotlin Ruby Rust Dart PHP
Multi Threading

Multi Threading #

Multithreading di Java adalah kemampuan untuk menjalankan beberapa alur eksekusi (thread) secara bersamaan dalam satu aplikasi. Hal ini memungkinkan program untuk melakukan beberapa tugas secara simultan, meningkatkan efisiensi dan performa terutama pada sistem dengan banyak prosesor. Java menyediakan berbagai cara untuk bekerja dengan thread, termasuk penggunaan kelas Thread, antarmuka Runnable, dan kerangka kerja Executor.

Konsep Dasar #

  • Thread: Unit terkecil dari eksekusi dalam Java. Setiap thread berjalan secara bersamaan dengan thread lainnya.
  • Concurrency: Kemampuan untuk menjalankan beberapa thread secara bersamaan.
  • Synchronization: Mekanisme untuk mengontrol akses thread ke sumber daya bersama agar tidak terjadi konflik.

Membuat dan Menjalankan Thread #

Ada dua cara utama untuk membuat thread di Java:

  1. Mengimplementasikan Antarmuka Runnable
  2. Mengextends Kelas Thread

Antarmuka Runnable #

Antarmuka Runnable harus diimplementasikan oleh kelas yang mendefinisikan metode run(). Thread kemudian dapat dibuat dengan mempassing instance Runnable ke konstruktor Thread.

Contoh:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getId() + " Value: " + i);
            try {
                Thread.sleep(500); // Menunggu 500 ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new MyRunnable());
        Thread thread2 = new Thread(new MyRunnable());
        
        thread1.start(); // Memulai thread1
        thread2.start(); // Memulai thread2
    }
}

Kelas Thread #

Anda dapat membuat thread dengan mengextends kelas Thread dan override metode run().

Contoh:

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getId() + " Value: " + i);
            try {
                Thread.sleep(500); // Menunggu 500 ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        Thread thread1 = new MyThread();
        Thread thread2 = new MyThread();
        
        thread1.start(); // Memulai thread1
        thread2.start(); // Memulai thread2
    }
}

Synchronization #

Jika beberapa thread mengakses sumber daya yang sama, Anda perlu memastikan bahwa hanya satu thread yang dapat mengakses sumber daya tersebut pada satu waktu untuk menghindari kondisi balapan (race conditions). Ini dapat dilakukan menggunakan kata kunci synchronized.

Contoh:

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class SynchronizationExample {
    public static void main(String[] args) {
        Counter counter = new Counter();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + counter.getCount());
    }
}

Executor Framework #

Java menyediakan kerangka kerja Executor untuk mengelola dan menjalankan thread secara lebih efisien daripada membuat dan mengelola thread secara manual.

Menggunakan ExecutorService #

ExecutorService menyediakan cara untuk mengelola kumpulan thread dan menjalankan tugas-tugas asynchronous.

Contoh:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ExecutorServiceExample {
    public static void main(String[] args) {
        // Membuat thread pool dengan 2 thread
        ExecutorService executor = Executors.newFixedThreadPool(2);

        Runnable task1 = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Task 1 - " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Runnable task2 = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Task 2 - " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        // Menjalankan tugas
        executor.submit(task1);
        executor.submit(task2);

        // Menutup executor dan menunggu tugas selesai
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}

Future dan Callable #

Jika Anda perlu mendapatkan hasil dari thread, Anda dapat menggunakan antarmuka Callable yang mirip dengan Runnable tetapi dapat mengembalikan nilai dan melemparkan pengecualian. Hasilnya dapat diambil dengan objek Future.

Contoh:

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 CallableExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(1);

        Callable<Integer> task = () -> {
            int sum = 0;
            for (int i = 1; i <= 10; i++) {
                sum += i;
                Thread.sleep(100);
            }
            return sum;
        };

        Future<Integer> future = executor.submit(task);

        try {
            Integer result = future.get(); // Mendapatkan hasil dari Callable
            System.out.println("Sum: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}

Kesimpulan #

Multithreading di Java memungkinkan aplikasi untuk melakukan banyak tugas secara bersamaan, meningkatkan efisiensi dan responsivitas. Anda dapat membuat dan mengelola thread menggunakan:

  • Antarmuka Runnable dan kelas Thread untuk menjalankan kode dalam thread baru.
  • Synchronized blocks atau methods untuk menghindari konflik dalam akses sumber daya bersama.
  • Executor framework untuk mengelola dan menjalankan thread dengan lebih efisien.
  • Callable dan Future untuk mendapatkan hasil dari thread.

Mengelola thread dengan benar adalah penting untuk menghindari masalah seperti deadlock, race conditions, dan masalah sinkronisasi.

« Build Tools
I/O »