Singleton

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one single instance. This is useful when exactly one object is needed to coordinate actions across the system. The term comes from the mathematical concept of a singleton.

Singleton

Singleton ensures that only one object of a particular class is ever created.

Synchronized

When a thread calls the synchronized method ‘test’ of the object (here object is an instance of ‘TheDemo’ class) it acquires the lock of that object, any new thread cannot call ANY synchronized method of the same object as long as previous thread which had acquired the lock does not release the lock.

synchronized blocks the next thread’s call to method test() as long as the previous thread’s execution is not finished. Threads can access this method one at a time. Without synchronized all threads can access this method simultaneously.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class SOP {
public static void print(String s) {
System.out.println(s+"\n");
}
}

public class TestThread extends Thread {
String name;
TheDemo theDemo;
public TestThread(String name,TheDemo theDemo) {
this.theDemo = theDemo;
this.name = name;
start();
}
@Override
public void run() {
theDemo.test(name);
}
}

public class TheDemo {
public synchronized void test(String name) {
for(int i=0;i<10;i++) {
SOP.print(name + " :: "+i);
try{
Thread.sleep(500);
} catch (Exception e) {
SOP.print(e.getMessage());
}
}
}
public static void main(String[] args) {
TheDemo theDemo = new TheDemo();
new TestThread("THREAD 1",theDemo);
new TestThread("THREAD 2",theDemo);
new TestThread("THREAD 3",theDemo);
}
}

Volatile

volatile has semantics for memory visibility. Basically, the value of a volatile field becomes visible to all readers (other threads in particular) after a write operation completes on it. Without volatile, readers could see some non-updated value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Foo extends Thread {

private volatile boolean close = false;

public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}

volatile is very useful to stop threads. One common example for using volatile is to use a volatile boolean variable as a flag to terminate a thread. In the above code segment, you need volatile because the thread reading close in the while loop is different from the one that calls close(). Without volatile, the thread running the loop may never see the change to close.

Double Checked Locking in Singleton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DoubleCheckLocking {

public static class SearchBox {
private static volatile SearchBox searchBox;

// private constructor
private SearchBox() {}

// static method to get instance
public static SearchBox getInstance() {
if (searchBox == null) { // first time lock
synchronized (SearchBox.class) {
if (searchBox == null) { // second time lock
searchBox = new SearchBox();
}
}
}
return searchBox;
}
}

Since you are obtaining lock on the SearchBox.class, only one thread will enter the synchronized block at a time. So the first thread enters then finds searchBox is null and initilize the instance and then leaves the synchronized block, then the second thread enter the block then it finds that the searchBox is not null because the first thread already created it so it will not create a new instance of searchBox.

The double checked pattern is used to avoid obtaining the lock every time the code is executed. If the call are not happening together then the first condition will fail and the code execution will not execute the locking thus saving resources. Its purpose is to prevent unnecessary synchronization, thereby keeping your code fast in a multi-threaded environment.

Why volatile

The real problem is that Thread A may assign a memory space for instance before it is finished constructing instance. Thread B will see that assignment and try to use it. This results in Thread B failing because it is using a partially constructed version of instance.

If we do not make the searchBox variable volatile then the Thread which is creating the instance of Singleton is not able to communicate to the other thread. So if Thread A is creating Singleton instance and just after creation, the CPU corrupts etc, all other threads will not be able to see the value of searchBox as not null and they will believe it is still assigned null.

The value of this variable will never be cached thread-locally: all reads and writes will go straight to “main memory”; Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.

Use cases

  • The logging class
  • Managing a connection to a database
  • File manager
  • Caching in Singleton