Java Object Level Lock

In this tutorial, we will learn about the concept of object level locks in Java, use cases of implementing locks along with the working examples of it.

Object Level Lock

In Java, object level lock concept gives a clear understanding on how to handle the shared resources in a controller manner while multiple threads trying to access and modifies shared resource state during run-time.

Object lock allows only one thread can access or modifies a shares resource (or) it provides a mutual exclusive lock on a shared resource.

Why Object Level Lock?

Consider an example of an application for an online store, in this store multiple users can purchase the available goods, multiple threads can access the store goods to fulfil the purchase orders. Suppose we have only one item left in the store but two users trying to purchase, without locks two threads can access the item and fulfil the order but only one item is present and this causes the problem to the store vendor.

If we reduce number of threads can lead to performance issues, to handle this kind of problems applying an object level lock on store items will be the perfect solution.

To apply lock on objects, we need to use the keyword synchronized, this allows getting lock on a particular object. Locks can be applied at method level or on individual data member of a class.

Syntax:

Method level:

public synchronized void incrementMethod() {
}

Individual data member:

public  void incrementMethod() {
	synchronized(this.dataMember) {
	}
}

Note: Locks cannot be applied individually on primitive data types.

Object lock example for method level:

In this example, we will implement lock over method level of an object.

CopiedCopy Code
public class ObjectLockMethod implements Runnable{
	LockMethod lock;
	public ObjectLockMethod(LockMethod lock) {
		this.lock = lock;
	}
	public static void main(String[] args) {
		LockMethod lock = new LockMethod(10);
		Thread t1 = new Thread(new ObjectLockMethod(lock),"T1");
		Thread t2 = new Thread(new ObjectLockMethod(lock),"T2");
		Thread t3 = new Thread(new ObjectLockMethod(lock),"T3");
		t1.start();
		t2.start();
		t3.start();
	}
	@Override
	public void run() {
		while(true) {
			int counterValue = this.lock.getCounter();
			if(counterValue==0)
				break;
			this.lock.decrementCounter();
		}
	}
}
class LockMethod {
	int counter;
	LockMethod(int counter) {
		this.counter = counter;
	}
	public synchronized int getCounter() {
		return this.counter;
	}
	public synchronized void decrementCounter() {
		System.out.println("Counter decremented by :"+Thread.currentThread().getName());
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {}
		this.counter--;
		System.out.println("Counter value :"+this.counter);
	}
}

Output:

Counter decremented by :T1
Counter value :9
Counter decremented by :T1
Counter value :8
Counter decremented by :T1
Counter value :7
Counter decremented by :T3
Counter value :6
Counter decremented by :T2
Counter value :5
Counter decremented by :T1
Counter value :4
Counter decremented by :T3
Counter value :3
Counter decremented by :T2
Counter value :2
Counter decremented by :T1
Counter value :1
Counter decremented by :T1
Counter value :0

Explanation:

In the above example, we have created three threads with the names T1,T2 and T3 by extending Runnable interface. Same LockMethod class object is passed to all threads, this LockMethod contains two synchronized methods given as getCounter() and decrementCounter(), one method prints value of counter and other decrements counter value.

In object level lock, only one thread can access its methods. Here on LockMethod class object applied a lock hence only one thread can access those methods. All three threads accessed those synchronized methods and printed counter values. And in the run method, checking if counter value is zero then while loop exited and no more instruction to process in run method and thereby all threads complete its execution.

Object lock example for individual data-member:

In this example, we will apply lock on Individual data-member of a class.

CopiedCopy Code
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class IndividualDatamemberLock implements Runnable {
	List<Integer> lock;
	public IndividualDatamemberLock(List<Integer> lock) {
		this.lock = lock;
	}
	public int consumeElement() {
		synchronized (this.lock) {
			if(this.lock.size()==0)//In case size is zero return
				return 0;
			Integer counterValue = this.lock.get(0);
			this.lock.remove(counterValue);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {}
			System.out.println("Array Element "+counterValue+" consumed by :"+Thread.currentThread().getName());
			return this.lock.size();
		}
	}
	public static void main(String[] args) {
		Integer intValue[] = {1,2,3,4,5,6,7};
		List<Integer> counter = new ArrayList(Arrays.asList(intValue));
		Thread t1 = new Thread(new IndividualDatamemberLock(counter), "T1");
		Thread t2 = new Thread(new IndividualDatamemberLock(counter), "T2");
		Thread t3 = new Thread(new IndividualDatamemberLock(counter), "T3");
		t1.start();// starting threads
		t2.start();
		t3.start();
	}
	@Override
	public void run() {
		while (this.consumeElement()>0) ;
	}
}

Output:

Array Element 1 consumed by :T1
Array Element 2 consumed by :T3
Array Element 3 consumed by :T3
Array Element 4 consumed by :T2
Array Element 5 consumed by :T3
Array Element 6 consumed by :T3
Array Element 7 consumed by :T1

Conclusion:

In this tutorial, we have covered what is object level lock and objective of it along with the working examples of it.