Runnable interface in Java

digitization, transformation, binary

The Runnable interface in Java

The runnable interface should be implemented by any class whose instances are intended to be executed by a thread(a subclass of Thread class). The class must define a method called run() in its body. the run() method has no argument. Any class that implements this interface can provide the body of a thread inside the run method.

The structure of the Runnable interface is given below:

public interface java.lang.Runnable{
//Method:
public abstract void run();
} 

The details of the method are as follows

Ads code goes here
public abstract void run();

When a Thread object starts running a thread, it associates executable code with the thread by calling a Runnable object’s run() method. The subsequent behavior of the thread is controlled by the run() method. Thus, a class that wants to perform certain operations in a separate thread should implement the Runnable interface and define an appropriate run() method. When the run() method called by a Thread object returns or throws an exception, the thread dies.

When an object implements Runnable interface, it creates a thread. To start the thread, the Object’s start() method is called from a separate thread. (Calling thread).

If mt is an instance of Thread, then mt.start() and mt.run() are two different things. Calling mt.run() will execute the run() method in the same thread which is calling this method. It won’t create a new thread. On the other hand, if mt.start() is called, it creates a new thread and executes the things in the new thread. So if any preconditions are there before the run() method will be ignored if only mt.run() is called. This is a popular Interface example in java.

READ  Abstract Class SocketImpl in Java

let’s see an example of Runnable Interface

The Account class is having two synchronized methods deposit and withdraw.

public class Account {
	int balance = 0;
	void displayBalance() {
		
		System.out.println("Account No"+accountNo+"Balamce"+balance);
	}
	synchronized void deposit (int amount) {
		balance=balance+amount;
		System.out.println("Account No creadited with "+amount+"new balance"+balance);
		displayBalance();
	}
	synchronized void withdraw(int amount) {
		balance=balance-amount;
		System.out.println("Account No debited with "+amount+"new balance"+balance);
		displayBalance();
	}
}

Let’s create the Depositor class

public class TransactionDeposit implements Runnable {
Account AccountX;
private int amount;

TransactionDeposit(Account AccountX,int amount)
{
	this.AccountX=AccountX;
	this.amount=amount;
	new Thread(this).start();
}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		AccountX.diposit(amount);
		
	}
}

Let’s create the Withdrawer class

public class TransactionWithDraw implements Runnable{
	Account AcountY;
	private int amount;

	TransactionWithDraw(Account AcountY,int amount)
	{
		this.AccountY=AcountY;
		this.amount=amount;
		new Thread(this).start();
	}
		@Override
		public void run() {
			// TODO Auto-generated method stub
			AccountY.withdraw(amount);
			
		}

}

For both the above-written methods synchronized is used for deposit and withdrawal so that these methods will never run simultaneously.

Alternatively, if we want to design a class that was not designed for multithread access and thus has a non-syncronized method(s), then the methods can be made synchronous by declaring an object synchronized. This declaration when precedes a block then reference of any methods of that object in the block will be synchronized.

Example:

synchronized(Object)
{
block of statement(s);
}

Where Object is any object reference,In this example we can remove the synchronized keyword from deposit() and withdraw(). Then the modified code will be as follows:
Deposit() method:

public void run(){
synchronized(AcountX){
AccountX.deposit(amount)
}
}

similarly, the withdraw() method will be:

public void run(){
synchronized(AcountY){
AccountX.withdraw(amount)
}
}

Now let’s create our actual class:

public class MyTransaction {

	public static void main(String[] args) {
		Account abc=new Acount();
		abc.balance=1000;
		TransactionDeposit t1;
		TransactionWithDraw t2;
		t1= new TransactionDeposit(abc,500);
		t2= new TransactionWithDraw(abc,900);
}
}

The output of the code:
Account No creadited with 500new balance1500
Account Balamce1500
Account No debited with 900new balance600
Account Balamce600

READ  HashSet Concept Simplified In Java

Let’s see one more example:
Here we will have one producer class that keeps on producing numbers and one consumer class that keeps on consuming those numbers.


public class QGeneral {
int n=0;
boolean flag=false;
synchronized void put(int n) {
	if(flag) {
		try {			wait();
		}
	
	catch(InterruptedException e) {}
    this.n=n;
    System.out.println("Produce"+n);
    flag=true;
    notify();
}
}
	synchronized int get() {
		if(!flag) {
			try {
				wait();
			}
			catch(InterruptedException e) {}
			System.out.println("Consumed"+n);
			flag=false;
			notify();
			
		}
		return n;
	}
}

QGeneral has two parallel methods

  • ProducerQ (put)
  • ConsumerQ (get)

Now ProducerQ is written as:


public class ProducerQ implements Runnable {
	QGeneral q;
	ProducerQ(QGeneral q){
		this.q=q;
		new Thread(this).start();
	}
	public void run() {
		int i=0;
		while(true)
			q.put(i++);
	}
}

Now ConsumerQ is written as:


public class ConsumerQ implements Runnable {
	QGeneral q;
	ConsumerQ(QGeneral q){
		this.q=q;
		new Thread(this).start();
	}
	public void run() {
		int i=0;
		while(true)
			q.get();
	}
}

Now the test class is written as:

public class TestQ {

	public static void main(String[] args) {
		QGeneral q=new QGeneral();
		new ProducerQ(q);
		new ConsumerQ(q);

	}

}

Share and Enjoy !

Leave a Comment

Your email address will not be published. Required fields are marked *