Calling Multiple Synchronized Methods

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 13

Calling multiple synchronized methods

Simultaneously through Java Threads

The following document assumes basic knowledge of threads from


Programmer and shows some jugglery with threads.

Date written:
04/21/2011

Declaration:
I hereby declare that this document is based on my personal experiences of
my project. To the best of my knowledge, this document does not contain any
material that infringes the copyrights of any other individual or organization
including the customers of Infosys.

Submitted By:
Prakhar Deep Gupta
Contents
Topics Page Number

1) Some basic facts about threads


2

2) (Switching threads) 4
3) What is Synchronization
7
a. Thread Interference 7
b. Synchronized Methods 8
c. Intrinsic Locks and Synchronization 9
Locks In Synchronized Methods 9
4) Creating Deadlocks 9
5) How to improve concurrency 11

A) Some basic facts about threads

Multi Threading In JAVA Page 2 of 13


1. The main () method itself is a thread.

For e.g. : This is a perfectly valid program.

public class BasicThreads {

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

System.out.println ("printing a line");

Thread.sleep(2000); //valid Statement

System.out.println ("printing a line");

The main thread need not extend the Thread class.

The above statement Thread.sleep(2000); //valid Statement makes


the main thread sleep for 2000 milliseconds before main executes
again. However one has to add the line throws InterruptedException in
the main method for the above statement to work.

2. The thread scheduling is done by the OS and it cannot be


controlled by the programmer.

For e.g.
public class ExampleOfThread extends Thread
{
public void run()
{
System.out.println (“Inside Thread”);
}
}

public class BasicThreads {

Multi Threading In JAVA Page 3 of 13


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

System.out.println ("printing a line");

Thread t1 = new ExampleThread();

Thread t2 = new ExampleOfThread();

t1.start();

t2.start();

System.out.println ("printing a line");

The above code does not guarantee that thread t1 will start before t2.
Although in most of the cases this will be true, it cannot be taken for
granted.

3. All the threads called in the main method are executed after all
statements in the main thread have been executed. However,
if the main thread calls sleep(long) method as shown in the
first example above, in which case the control is relinquished
to some other thread.

Also in the above program the output is :

printing a line

printing a line

Inside Thread

Inside Thread

And not

printing a line

Multi Threading In JAVA Page 4 of 13


Inside Thread

Inside Thread

printing a line

This is because the main thread executes first and then the threads
inside it.

B) How to print odd numbers from one thread


and even numbers from another thread?
(Switching threads)
One of the more interesting problems is how to alternate 2
threads. Suppose we want the threads to “switch” i.e. we want
one thread to do something and then depending on the result
another thread performs some other action. They operate on the
same data member.
For this, there can be a possible solution:
1) Make the data member as static. But this will violate the OOP
principle of data hiding. If the member is public then it can be
modified even without creating an object. It can create a
security issue as far as contents of the data member in
question is concerned. Also, there is the concept of thread
safety is not implemented.

Also, a simple t1.start() and t2.start may not work as explained


earlier.
The other way is given below.

package test2;
import static java.lang.System.out;
public class AlternatingThreads
{
public static void main(String[] args) {
SyncingClass SC = new SyncingClass();
EvenPrinter even = new EvenPrinter (SC);
OddPrinter odd = new OddPrinter (SC);

}
}

Multi Threading In JAVA Page 5 of 13


class SyncingClass {
boolean isOdd = false;
int i = 0;
synchronized int getOdd() {
while(!isOdd) {
try {
System.out.println ("Waiting for Even to turn Odd");
wait();
} catch(InterruptedException e) {}
}
isOdd = false;
//System.out.println("Odd = = " + i++);
notifyAll();
return i++;
}
synchronized int getEven() {
while(isOdd) {
try {
System.out.println ("Waiting for Odd to turn even");
wait();
} catch(InterruptedException e) {}
}
isOdd = true;
//System.out.println("Even = = " + i++);
notifyAll();
return i++;
}
}
class OddPrinter implements Runnable {
SyncingClass q;
Thread t;
OddPrinter (SyncingClass q) {
System.out.println ("Inside Oddprinter constructor");
this.q = q;
t = new Thread(this," --Odd-- ");
t.start();
}

public void run() {


for(int i=0;i<10;i++)
System.out.println("Odd === "+q.getOdd());
System.out.println("-- End thread Odd --");
}
}

Multi Threading In JAVA Page 6 of 13


class EvenPrinter implements Runnable {
SyncingClass q;
Thread t;
EvenPrinter (SyncingClass q) {
System.out.println ("Inside Evenprinter constructor");
this.q = q;
t = new Thread(this," --Even-- ");
t.start();
}
public void run() {
for(int i=0;i<10;i++)
System.out.println("Even ==="+q.getEven());
System.out.println("-- End thread Even --");
}
}

Here first the threads for the Even and Odd numbers are created
and an object on which the operations need to be performed is
passed at the time of creation. Whenever some operation is to be
performed, the data members of the object that was passed is
used.

The operation itself is performed by the different classes.


This not only ensures thread safety but also achieves the
intended purpose. This logic can be extended to ‘n’ number of
threads to perform switches between them.

C) What is Synchronization and why is it


needed?
Another issue that comes up when one talks about threads.
Threads share certain data members. This can create a
concurrency issue.
Synchronization is the capability to control the access of multiple
threads to share resources. Without synchronization it is possible
for one thread to modify a shared object while another thread is
in the process of using or updating that object's value .This often
leads to an error.

Thread Interference

Multi Threading In JAVA Page 7 of 13


Consider a simple class called Total

class Total {
private int sum = 0;

public void increment() {


sum++;
}

public void decrement() {


sum--;
}

public int value() {


return sum;
}

}
Total is designed so that each call to increment will add 1 to sum, and each call
to decrement will subtract 1 from sum. However, if the SAME Total object is
referenced from multiple threads, interference between threads may not give the
expected outcomes

Thread Interference is said to take place when two operations, running in


different threads, but acting on the same data, interleave. This means that the
two operations consist of multiple steps, and the sequences of steps overlap.

It might not seem possible for operations on instances of Total to interleave, since
both operations on sum are seemingly single statements. However, even simple
statements can translate to multiple steps by the virtual machine. For e.g.

1. Retrieve the current value of sum.


2. Increment the retrieved value by 1.
3. Store the incremented value back in sum.

The expression sum-- can be decomposed into multiple operations the same way.

Suppose Thread X invokes increment at about the same time Thread Y


invokes decrement. If the initial value of sum is 0, their interleaved actions might
follow this sequence:

1. Thread A: Retrieve c.
2. Thread B: Retrieve c.
3. Thread A: Increment retrieved value; result is 1.
4. Thread B: Decrement retrieved value; result is -1.
5. Thread A: Store result in c; c is now 1.

Multi Threading In JAVA Page 8 of 13


6. Thread B: Store result in c; c is now -1.

But this sequence is unpredictable as explained earlier. So any of the results may
be lost or the result maybe correct also.
There is no fix for it. So one has to prevent this situation from happening.
This is where synchronization comes into play.

Synchronized Methods

The Java programming language provides two basic synchronization


idioms: synchronized methods and synchronized statements.

To make a method synchronized, simply add the synchronized keyword to its


declaration:

class Total {
private int sum = 0;

public synchronized void increment() {


sum++;
}

public synchronized void decrement() {


sum--;
}

public int value() {


return sum;
}

It is not possible for two invocations of synchronized methods on the same object
to interleave. When one thread is executing a synchronized method for an object,
all other threads that invoke synchronized methods for the same object block
(suspend execution) until the first thread is done with the object.

Intrinsic Locks and Synchronization


Synchronization is built around an internal entity known as the intrinsic
lock or monitor lock. (The API specification often refers to this entity simply as a
"monitor.") Intrinsic locks play a role in both aspects of synchronization:
enforcing exclusive access to an object's state and establishing happens-before
relationships that are essential to visibility.

Multi Threading In JAVA Page 9 of 13


Every object has an intrinsic lock associated with it. By convention, a
thread that needs exclusive and consistent access to an object's fields
has to acquire the object's intrinsic lock before accessing them, and
then release the intrinsic lock when it's done with them. A thread is
said to own the intrinsic lock between the time it has acquired the lock
and released the lock. As long as a thread owns an intrinsic lock, no
other thread can acquire the same lock. The other thread will block
when it attempts to acquire the lock.

Locks In Synchronized Methods


When a thread invokes a synchronized method, it automatically acquires the
intrinsic lock for that method's object and releases it when the method returns.
The lock release occurs even if the return was caused by an uncaught exception.
Synchronized methods enable a simple strategy for preventing
thread interference and memory consistency errors: if an object
is visible to more than one thread, all reads or writes to that
object's variables are done through synchronized methods. (An
important exception: final fields, which cannot be modified after
the object is constructed, can be safely read through non-
synchronized methods, once the object is constructed)

D) LIMITATIONS OF SYNCHRONIZATION: How


to create a deadlock?
The limitation and consequences of the line highlighted in blue in
the previous section is shown here. The previous limitation can
be used to create a deadlock in a program. This program shows
how to do that.
public class AnotherDeadLock {
public static void main(String[] args) {
final Object resource1 = "resource1";
final Object resource2 = "resource2";
// t1 tries to lock resource1 then resource2
Thread t1 = new Thread() {
public void run() {
// Lock resource 1
synchronized (resource1) {
System.out.println("Thread 1: locked resource 1");

try {
Thread.sleep(50);
} catch (InterruptedException e) {

Multi Threading In JAVA Page 10 of


13
}

synchronized (resource2) {
System.out.println("Thread 1: locked resource 2");
}
}
}
};

// t2 tries to lock resource2 then resource1


Thread t2 = new Thread() {
public void run() {
synchronized (resource2) {
System.out.println("Thread 2: locked resource 2");

try {
Thread.sleep(50);
} catch (InterruptedException e) {
}

synchronized (resource1) {
System.out.println("Thread 2: locked resource 1");
}
}
}
};
// The deadlock will occur,
// and the program will never exit.
t1.start();
t2.start();
}
}

E) How to improve concurrency using


Synchronized statements instead of
synchronized methods?
Let us say that an object has two instance fields, F1 and F2, that are
never used together. All updates of these fields must be synchronized,
but there's no reason to prevent an update of F1 from being
interleaved with an update of F2 — and doing so reduces concurrency
by creating unnecessary blocking.

Now if we make methods synchronized, then for 1 object, only 1


synchronized method can be called at one time. This is desirable if the

Multi Threading In JAVA Page 11 of


13
fields are related; but if the fields are unrelated, then it reduces
efficiency of the program as this locking is undesirable.

So instead of using synchronized methods or otherwise using the lock


associated with this, we create two objects solely to provide locks.

To understand this, one needs to understand to these concepts


first

Using synchronized on methods is really just shorthand


(assume class is SomeClass):

synchronized static void foo() {


...
}

is same as

static void foo() {


synchronized(SomeClass.class) {
...
}
}

synchronized void foo() {


...
}

is same as

void foo() {
synchronized(this) {
...
}
}

For e.g.

You can use any object as the lock. If you want to lock subsets of static
methods, you can

class SomeClass {
private static final Object LOCK_1 = new Object() {};
private static final Object LOCK_2 = new Object() {};
static void foo() {

Multi Threading In JAVA Page 12 of


13
synchronized(LOCK_1) {...}
}
static void fee() {
synchronized(LOCK_1) {...}
}

static void fee() {


synchronized(LOCK_2) {...}
}
static void foo() {
synchronized(LOCK_2) {...}
}
}

HOW TO CALL MULTIPLE SYNCHRONIZED METHODS OF THE SAME


OBJECTS USING SYNCHRONIZED STATEMENTS

public class TwoConcurrentMethods {


private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();

public void inc1() {


synchronized(lock1) {
c1++;
}
}

public void inc2() {


synchronized(lock2) {
c2++;
}
}
}
But this way with extreme care. One must be absolutely sure that it really is safe to
interleave access of the affected fields.

Multi Threading In JAVA Page 13 of


13

You might also like