Java Exercise
In this exercise, you will create a Java program that demonstrates the use of **synchronization** and **concurrency** to handle access to shared resources among multiple threads. You will use the `synchronized` mechanism to ensure that only one thread at a time can access critical methods. Additionally, you'll learn how to use the `wait()` and `notify()` methods to coordinate thread execution and enable communication between them.
Instructions:
- Create a class named
BankAccount
that holds a balance shared across multiple threads.
- Define a
deposit
method and a withdraw
method, both synchronized to prevent two threads from modifying the balance simultaneously.
- Use the
wait()
and notify()
methods to manage wait conditions and notify threads when the balance is insufficient to withdraw money.
- In the main method, create multiple threads that simulate deposits and withdrawals, and demonstrate how synchronization and concurrency enable safe access to the resource. Shared.
This exercise will help you understand how to manage multiple threads in Java, ensuring that shared resources are handled safely and efficiently, avoiding concurrency issues such as race conditions.
View Example Code
// BankAccount class simulating deposit and withdrawal operations with synchronization
class BankAccount {
private double balance = 1000; // Initial balance
// Synchronized method to deposit money
public synchronized void deposit(double amount) {
balance += amount;
System.out.println("Deposited: " + amount + ", New balance: " + balance);
notify(); // Notify if any thread is waiting
}
// Synchronized method to withdraw money
public synchronized void withdraw(double amount) throws InterruptedException {
while (balance < amount) {
System.out.println("Insufficient balance to withdraw: " + amount + ". Waiting...");
wait(); // Wait until there is enough balance
}
balance -= amount;
System.out.println("Withdrawn: " + amount + ", New balance: " + balance);
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount();
// Create a thread to perform a deposit
Thread depositor = new Thread(() -> {
account.deposit(500);
});
// Create a thread to perform a withdrawal
Thread withdrawer = new Thread(() -> {
try {
account.withdraw(1200); // Try to withdraw more than the available balance
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// Start the threads
depositor.start();
withdrawer.start();
// Wait for both threads to finish
try {
depositor.join();
withdrawer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output:
Insufficient balance to withdraw: 1200. Waiting...
Deposited: 500.0, New balance: 1500.0
Withdrawn: 1200.0, New balance: 300.0
This program demonstrates how concurrency issues are handled in Java using synchronization. The BankAccount
class has two synchronized methods: deposit
and withdraw
. The thread performing the withdrawal will wait if the balance is insufficient, while the depositing thread will notify the waiting threads once there is a sufficient balance. This shows how synchronization and interthread communication mechanisms (such as wait()
and notify()
) can solve problems of concurrent access to shared resources.