MenuBar

Kata Mutiara

"Keberhasilan merupakan tetesan dari jeri-payah perjuangan, luka, pengorbanan dan hal-hal yang mengejutkan. Kegagalan merupakan tetesan dari kemalasan, kebekuan, kelemahan, kehinaan dan kerendahan"

ANIMASI TULISAN BERJALAN

Thursday, January 16, 2025

Implementasi konsep Thread, Race Condition, Deadlock, dan Synchronization

contoh implementasi konsep thread, race condition, deadlock, dan synchronization dalam konteks aplikasi kredit atau keuangan:


Studi Kasus: Simulasi Transaksi Bank

Skenario

  • Ada dua akun bank dengan saldo masing-masing.
  • Beberapa thread mewakili transaksi simultan seperti transfer antar akun.
  • Tujuan: Menghindari masalah race conditiondeadlock, dan menggunakan teknik synchronization untuk memastikan konsistensi data.

1. Race Condition

Masalah:

  • Jika dua thread mencoba mengakses dan memodifikasi saldo akun secara bersamaan tanpa sinkronisasi, hasil akhirnya bisa salah.

Kode Bermasalah (Race Condition):

java

public class BankAccount {
    private int balance;

    public BankAccount(int balance) {
        this.balance = balance;
    }

    public void deposit(int amount) {
        balance += amount; // Tidak aman tanpa sinkronisasi
    }

    public void withdraw(int amount) {
        balance -= amount; // Tidak aman tanpa sinkronisasi
    }

    public int getBalance() {
        return balance;
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                account.deposit(10);
                account.withdraw(10);
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final Balance: " + account.getBalance());
    }
}

Output Potensial (Race Condition):
sql

Final Balance: 1000 (bisa benar)
Final Balance: 980 (atau hasil lain karena race condition)

2. Solusi: Synchronization

Gunakan synchronized untuk memastikan hanya satu thread yang dapat mengakses metode deposit atau withdraw pada satu waktu.

Kode dengan Synchronization:

java

public class BankAccount {
    private int balance;

    public BankAccount(int balance) {
        this.balance = balance;
    }

    public synchronized void deposit(int amount) {
        balance += amount;
    }

    public synchronized void withdraw(int amount) {
        balance -= amount;
    }

    public synchronized int getBalance() {
        return balance;
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                account.deposit(10);
                account.withdraw(10);
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final Balance: " + account.getBalance());
    }
}

Output (Sinkronisasi):

yaml

Final Balance: 1000

3. Deadlock

Masalah:

  • Jika dua thread memegang kunci (lock) pada dua objek berbeda dan mencoba mengakses kunci yang dipegang oleh thread lain, terjadi deadlock.

Kode Deadlock:

java

public class BankAccount {
    private final int id;
    private int balance;

    public BankAccount(int id, int balance) {
        this.id = id;
        this.balance = balance;
    }

    public int getId() {
        return id;
    }

    public synchronized void transfer(BankAccount target, int amount) {
        synchronized (target) {
            this.balance -= amount;
            target.balance += amount;
        }
    }
}

Perbaikan dengan ReentrantLock:

java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BankAccount {
    private final int id;
    private int balance;
    private final Lock lock = new ReentrantLock();

    public BankAccount(int id, int balance) {
        this.id = id;
        this.balance = balance;
    }

    public boolean transfer(BankAccount target, int amount) {
        if (this.lock.tryLock()) {
            try {
                if (target.lock.tryLock()) {
                    try {
                        this.balance -= amount;
                        target.balance += amount;
                        return true;
                    } finally {
                        target.lock.unlock();
                    }
                }
            } finally {
                this.lock.unlock();
            }
        }
        return false; // Gagal jika kunci tidak tersedia
    }
}


4. ExecutorService dan java.util.concurrent

Untuk menangani banyak thread dengan lebih mudah, gunakan ExecutorService.

Kode dengan ExecutorService:

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

public class Main {
    public static void main(String[] args) {
        BankAccount account1 = new BankAccount(1, 1000);
        BankAccount account2 = new BankAccount(2, 1000);

        ExecutorService executor = Executors.newFixedThreadPool(2);

        Runnable task1 = () -> account1.transfer(account2, 100);
        Runnable task2 = () -> account2.transfer(account1, 200);

        executor.submit(task1);
        executor.submit(task2);

        executor.shutdown();

        while (!executor.isTerminated()) {
        }

        System.out.println("Account 1 Balance: " + account1.getBalance());
        System.out.println("Account 2 Balance: " + account2.getBalance());
    }
}

Output:

yaml

 Account 1 Balance: 1100
 Account 2 Balance: 900

Konsep yang Digunakan:

  1. Race Condition:
    • Dicegah dengan sinkronisasi (synchronized atau ReentrantLock).
  2. Deadlock:
    • Dicegah dengan tryLock() atau menghindari penguncian bersamaan.
  3. Threading:
    • Menangani banyak thread menggunakan ExecutorService.
  4. Concurrency Utilities:
    • Gunakan kelas seperti ReentrantLock untuk pengendalian kunci yang lebih fleksibel.

Contoh ini mencakup skenario umum dalam aplikasi keuangan seperti transaksi antar akun dengan memastikan keamanan data dan menghindari masalah threading.

No comments:

Post a Comment

iklan

iklan