- Java Programming Basics
- Java Tutorial
- Java Overview
- Java Environment Setup
- Java Program Structure
- Java Basic Syntax
- Java First Program
- Java Constants
- Java Separators
- Java Keywords
- Java Data Types
- Java Data Types
- Java Integers
- Java Floating Point
- Java Characters
- Java Booleans
- Java Numbers
- Java Programming Variables
- Java Variables
- Java Variable Types
- Java Variable Scope
- Java Type Conversion
- Java Type Casting
- Java Auto Type Promotion
- Java Type Promotion Rules
- Java Programming Arrays
- Java Arrays
- Java One Dimensional Array
- Java Multidimensional Array
- Java Programming Operators
- Java Operators
- Java Arithmetic Operators
- Java Increment Decrement
- Java Bitwise Operators
- Java Left Shift
- Java Right Shift
- Java Relational Operators
- Java Boolean Logical Operators
- Java Ternary(?) Operator
- Java Operator Precedence
- Java Control Statements
- Java Decision Making
- Java if if-else if-else-if
- Java switch Statement
- Java Loops
- Java while Loop
- Java do-while Loop
- Java for Loop
- Java for-each Loop
- Java Nested Loops
- Java break Statement
- Java continue Statement
- Java Class Object Method
- Java Classes and Objects
- Java Class
- Java Object
- Java new Operator
- Java Methods
- Java Constructors
- Java this Keyword
- Java Stack
- Java Overloading Recursion
- Java Method Overloading
- Java Constructor Overloading
- Java Object as Parameter
- Java Call by Value Reference
- Java Returning Objects
- Java Recursion
- Java Modifier Types
- Java Encapsulate Poly String
- Java Encapsulation
- Java Polymorphism
- Java Nested Inner Class
- Java Strings
- Java Command Line Arguments
- Java Variable Length Arguments
- Java Inheritance Abstraction
- Java Inheritance
- Java super Superclass
- Java Multilevel Hierarchy
- Java Method Overriding
- Java Abstraction
- Java Packages Interfaces
- Java Packages
- Java Access Protection
- Java Import Statement
- Java Interfaces
- Java Programming Exceptions
- Java Exception Handling
- Java try catch
- Java throw throws
- Java finally Block
- Java Built In Exceptions
- Java Exception Subclasses
- Java Chained Exceptions
- Java Multithreading
- Java Multithreading
- Java Thread Model
- Java Main Thread
- Java Create Thread
- Java Thread Priorities
- Java Synchronization
- Java Inter Thread Communication
- Java Suspend Resume Stop Thread
- Java Get Thread State
- Java Enum Autobox Annotation
- Java Enumerations
- Java Type Wrappers
- Java Autoboxing
- Java Annotation
- Java Marker Annotations
- Java Single Member Annotation
- Java Built In Annotations
- Java Type Annotations
- Java Repeating Annotations
- Java Data File Handling
- Java Files I/O
- Java Streams
- Java Read Console Input
- Java Write Console Output
- Java PrintWriter Class
- Java Read Write Files
- Java Automatically Close File
- Java Programming Advance
- Java Date and Time
- Java Regular Expressions
- Java Collections Framework
- Java Generics
- Java Data Structures
- Java Network Programming
- Java Serialization
- Java Send Email
- Java Applet Basics
- Java Documentation
- Java Programming Examples
- Java Programming Examples
Java Synchronization
When two or more threads need access to a shared resource, they need some way to ensure that the resource will be used by only one thread at a time. The process by which this is achieved is called synchronization. As you will see, Java provides a unique, language-level support for it.
Key to synchronization is the concept of monitor. A monitor is an object that is used as a mutually exclusive lock. Only one thread can own a monitor at a given time.
When a thread acquires a lock, it is said to have entered the monitor. All the other threads attempting to enter the locked monitor will be suspended until the first thread exits the monitor. These other threads are said to be waiting for the monitor. A thread that owns a monitor can re-enter the same monitor if it so desires.
You can synchronize your code in either of the two ways. Both involve the use of the synchronized keyword. Let's examine both.
Java synchronized Methods
Synchronization is easy in Java, because all objects have their own implicit monitor associated with them. To enter an object's monitor, just call a method that has been modified with synchronized keyword. While a thread is inside a synchronized method, all the other threads that try to call it (or any other synchronized method) on the same instance have to wait. To exit the monitor and relinquish control of the object to the next waiting thread, the owner of the monitor simply returns from the synchronized method.
Java synchronized Methods Example
To understand the need for synchronization, let's start with a simple example that does not use it, but should.
The following program has three simple classes. The first one, Callme, has a single method named call(). The call() method takes a String parameter called msg. This method tries to print the msg string inside of square brackets. The interesting thing to notice is that after call() prints the opening bracket and the msg string, it calls the Thread.sleep(1000), which pauses the current thread for one second.
The constructor of the next class, Caller, takes a reference to an instance of Callme class and a String, which are stored in target and msg, respectively. The constructor also creates a new thread that will call this object's run() method. The thread is started immediately. The run() method of the Caller calls the call() method on the target instead of Callme, passing in the msg string. Finally, the Synch class starts by creating a single instance of Callme, and three instances of Caller, each with a unique message string. The same instance of Callme is passed to each Caller.
/* Java Program Example - Java Synchronization * This program is not synchronized */ class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch(InterruptedException e) { System.out.println("Interrupted..!!"); } System.out.println("]"); } } class Caller implements Runnable { String msg; Callme target; Thread thr; public Caller(Callme trg, String str) { target = trg; msg = str; thr = new Thread(this); thr.start(); } public void run() { target.call(msg); } } class Synch { public static void main(String args[]) { Callme target = new Callme(); Caller obj1 = new Caller(target, "Hello"); Caller obj2 = new Caller(target, "Synchronized"); Caller obj3 = new Caller(target, "World"); /* wait for threads to end */ try { obj1.thr.join(); obj2.thr.join(); obj3.thr.join(); } catch(InterruptedException e) { System.out.print("Interrupted..!!"); } } }
Above Java program will produce the following output:
As you can see, by calling the sleep(), the call() method allows the execution to switch to another thread. This result in the mixed-up output of the three message strings. In the above program, nothing exists to stop all the three thread from calling the same method, on the same object, at the same time. This is known as a race condition, because the three threads are racing each other to complete the method. This example used sleep() method to make the effects repeatable and obvious. In most situations, a race condition is more subtle and less predictable, because you can't be sure when the context switch will occur. This can cause a program to run right one time and wrong the next.
To fix the preceding program, you must serialize access to call() i.e., you must restrict its access to only one thread at a time. To do this, you simply need to precede the call()'s definition with the keyword synchronized as shown below :
replace thisclass Callme { void call(String msg) { ...
by
class Callme { synchronized void call(String msg) { ...
This prevents the other threads from entering the call() while another thread is using it. After synchronized has been added to call(), the output of the above program will be :
Any time that you have a method, or a group of methods, that manipulates the internal state of an object in a multithreaded situation, you should use synchronized keyword to guard the state from the race conditions.
Remember, once a thread enters any synchronized method on an instance, no other thread can enter any other synchronized method on the same instance. However, non-synchronized methods on that instance will continue to be callable.
Java synchronized Statement
While creating the synchronized methods within classes that you create is an easy and effective means of achieving synchronization, it will not
work in all cases. To understand why, consider the following.
Imagine that you want to synchronize access to the objects of a class that was not designed for multithreaded access i.e., the class doest not use
synchronized methods. Further, this class was not created by you, but by a third party, and you do not have access to the
source code. Thus, you can't add synchronized to appropriate methods within the class. How can access to an object of this class
be synchronized? Fortunately, the solution to this problem is quite easy, you simply put calls to the methods defined by this class inside a
synchronized block.
Following is the general form of the synchronized statement :
synchronized(objRef) { // statements to be synchronized }
Here, objRef is a reference to the object being synchronized. A synchronized block ensures that a call to a synchronized method that is a member of objRef's class occurs only after the current thread has successfully entered the objRef's monitor.
Java synchronized Statement Example
Following is an alternative version of the preceding example, using a synchronized block within the run() method:
/* Java Program Example - Java Synchronization * This program is uses a synchronized block */ class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch(InterruptedException e) { System.out.println("Interrupted..!!"); } System.out.println("]"); } } class Caller implements Runnable { String msg; Callme target; Thread thr; public Caller(Callme trg, String str) { target = trg; msg = str; thr = new Thread(this); thr.start(); } /* synchronize calls to call() */ public void run() { synchronized(target) // synchronized block { target.call(msg); } } } class Synch { public static void main(String args[]) { Callme target = new Callme(); Caller obj1 = new Caller(target, "Hello"); Caller obj2 = new Caller(target, "Synchronized"); Caller obj3 = new Caller(target, "World"); /* wait for threads to end */ try { obj1.thr.join(); obj2.thr.join(); obj3.thr.join(); } catch(InterruptedException e) { System.out.print("Interrupted..!!"); } } }
Here, the call() method is not modified by synchronized. Instead, the synchronized statement is used inside the Caller's run() method. This causes the same correct output as the preceding example, because each thread waits for the prior one to finish before proceeding.
« Previous Tutorial Next Tutorial »