How to lock objects in Java?

Aviva 47 Published: 07/30/2024

How to lock objects in Java?

I'll make sure to respond in English!

In Java, locking objects is crucial when you want to ensure that only one thread can access and modify an object's state at a time. There are several ways to achieve this, depending on the requirements of your program.

1. Synchronized Methods

One way to lock objects is by using synchronized methods. When you declare a method as synchronized, it means that only one thread can execute this method at a time. If another thread tries to access the same method while it's already being executed, it will be blocked until the current thread finishes.

Here's an example:

public class BankAccount {

private int balance = 0;

public synchronized void withdraw(int amount) {

if (amount > balance) {

// Handle insufficient funds

}

balance -= amount;

}

public void deposit(int amount) {

balance += amount;

}

}

In this example, the withdraw method is declared as synchronized, which means that only one thread can call this method at a time. This ensures that two threads cannot simultaneously withdraw money from the same account.

2. Lock Objects

Another way to lock objects is by using explicit locks. You can create a Lock object and use its lock() and unlock() methods to control access to an object.

Here's an example:

public class BankAccount {

private Object lock = new Object();

private int balance = 0;

public void withdraw(int amount) {

synchronized (lock) {

if (amount > balance) {

// Handle insufficient funds

}

balance -= amount;

}

}

public void deposit(int amount) {

synchronized (lock) {

balance += amount;

}

}

}

In this example, we create a Lock object and use it to synchronize access to the balance variable. Only one thread can execute the critical section of code at a time.

3. Reentrant Locks

A reentrant lock allows a thread to lock an object multiple times without blocking other threads that might also be trying to lock the same object. This is useful when you need to perform nested locking operations.

Here's an example:

import java.util.concurrent.locks.ReentrantLock;

public class BankAccount {

private ReentrantLock lock = new ReentrantLock();

private int balance = 0;

public void withdraw(int amount) {

lock.lock();

try {

if (amount > balance) {

// Handle insufficient funds

}

balance -= amount;

} finally {

lock.unlock();

}

}

public void deposit(int amount) {

lock.lock();

try {

balance += amount;

} finally {

lock.unlock();

}

}

}

In this example, we use a reentrant lock to synchronize access to the balance variable. The lock() and unlock() methods are used to acquire and release the lock.

Conclusion

Locking objects in Java is an essential concept for building thread-safe programs. By using synchronized methods, lock objects, or reentrant locks, you can ensure that only one thread can access and modify an object's state at a time. This helps prevent data corruption and ensures the integrity of your program.

java lock example

I'll respond in English this time.

Java Lock Example:

Synchronization is a crucial aspect of programming that ensures only one thread can execute a particular section of code at any given time. This is achieved using locks, which are the core mechanism to control access to shared resources and ensure thread safety. Let's dive into an example of how to use Java locks effectively.

Example: Synchronized Access to Shared Resource

Consider a scenario where we have two threads, T1 and T2, that need to access a shared resource (a bank account) simultaneously. We want to ensure that only one thread can withdraw or deposit funds at any given time to prevent conflicts. To achieve this, we'll use Java's built-in locking mechanism.

Here's the code:

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class BankAccount {

private int balance = 0;

private Lock lock = new ReentrantLock();

public void deposit(int amount) {

try {

lock.lock();

try {

balance += amount;

System.out.println("Deposited " + amount + ". New balance is: " + balance);

} finally {

lock.unlock();

}

} catch (Exception e) {

// handle exceptions

}

}

public void withdraw(int amount) {

try {

lock.lock();

try {

if (balance >= amount) {

balance -= amount;

System.out.println("Withdrew " + amount + ". New balance is: " + balance);

} else {

System.out.println("Insufficient funds!");

}

} finally {

lock.unlock();

}

} catch (Exception e) {

// handle exceptions

}

}

public int getBalance() {

return balance;

}

}

In this example:

We create a BankAccount class that represents the shared resource (the bank account). The deposit and withdraw methods simulate operations on the account. We use the ReentrantLock to synchronize access to the account. This ensures that only one thread can execute these methods at any given time.

To test this example, we can create two threads (T1 and T2) that concurrently access the bank account:

public class Main {

public static void main(String[] args) throws InterruptedException {

BankAccount bankAccount = new BankAccount();

Thread t1 = new Thread(() -> {

for (int i = 0; i < 10; i++) {

bankAccount.deposit(i);

Thread.sleep(100); // simulate delay

}

});

Thread t2 = new Thread(() -> {

for (int i = 9; i > -1; i--) {

bankAccount.withdraw(i);

Thread.sleep(100); // simulate delay

}

});

t1.start();

t2.start();

t1.join();

t2.join();

}

}

In this test, we create two threads:

T1: Simulates depositing funds from 0 to 9 with a delay of 100ms between each operation. T2: Simulates withdrawing funds from 9 to 0 with a delay of 100ms between each operation.

When you run this test, you'll see that the deposit and withdraw methods execute serially, ensuring thread safety and preventing conflicts when accessing the shared resource (the bank account).

In conclusion, Java locks are an essential tool for achieving thread safety and controlling access to shared resources. By using constructs like ReentrantLock, we can ensure that only one thread can execute critical sections of code at any given time.

This example illustrates the use of Java locks in a real-world scenario where two threads need to access a shared resource (a bank account) concurrently.