1. Application scenarios of singleton mode
The Singleton Pattern ensures that a Ray = class has absolutely one instance in all cases and provides a global access point. The singleton pattern is the creation pattern. In practice, the singleton pattern is applied in Spring framework applications such as ApplicationContext, database connection pool, and so on.
2. Hungry singleton mode
The hanchian singleton pattern initializes the class as soon as it is loaded and creates the initialization object. It is absolutely thread-safe and is instantiated before threads exist, so there can be no access security issues.
-
Advantages: no lock, high efficiency. The user experience is better than the lazy singleton pattern.
-
Cons: Classes are initialized as they are loaded, taking up space and wasting memory when they are not being used.
The IOC container ApplicationContext in Spring is itself a typical Hunchman singleton pattern.
Let’s look at some code:
public class HungrySingleton {
// Static first, then dynamic
// Attribute first, method second
// First up, then down
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(a){}public static HungrySingleton getInstance(a){
returnhungrySingleton; }}Copy the code
There is another way to write this, using the mechanism of static code blocks:
public class HungryStaticSingleton {
private static final HungryStaticSingleton hungryStaticSingleton;
static {
hungryStaticSingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton(a){}public static HungryStaticSingleton getInstance(a){
returnhungryStaticSingleton; }}Copy the code
Both of these are very simple and easy to understand, and the Hunchman singleton pattern works well when there are fewer singletons. Now let’s look at a better way to write it.
3. Lazy singleton pattern
The lazy singleton pattern is characterized by the fact that the inner class is loaded only when called by the external class.
// Lazy singletons are instantiated only for external use
public class LazySimpleSingleton {
private LazySimpleSingleton(a) {}// Static block, common memory area
private static LazySimpleSingleton lazy = null;
public static LazySimpleSingleton getInstance(a) {
if (lazy == null) {
lazy = newLazySimpleSingleton (); }returnlazy; }}Copy the code
Then write a thread class to test it
public class ExectortTread implements Runnable {
@Override
public void run(a) {
LazySimpleSingleton lazySimpleSingleton = LazySimpleSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":"+ lazySimpleSingleton); }}Copy the code
Write a test class to test
public class LazySingletonTest {
public static void main(String[] args) {
Thread t1 = new Thread(new ExectortTread());
Thread t2 = new Thread(new ExectortTread());
t1.start();
t2.start();
System.out.println("The end"); }}Copy the code
After several runs, sometimes the results are the same, sometimes different, thread safety risks still exist. For optimization, add the synchronized keyword to getInstance() to make the method synchronous.
// Lazy singletons are instantiated only for external use
public class LazySimpleSingleton {
private LazySimpleSingleton(a) {}// Static block, common memory area
private static LazySimpleSingleton lazy = null;
public synchronized static LazySimpleSingleton getInstance(a) {
if (lazy == null) {
lazy = new LazySimpleSingleton();
}
returnlazy; }}Copy the code
Although the thread safety problem is solved by using synchronized, a large number of threads will be blocked and the program performance will be affected in the case of a large number of threads and limited resources.
Here’s a thread-safe way to improve performance. A singleton pattern for double-checked locks.
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazy = null;
private LazyDoubleCheckSingleton(a){}public static LazyDoubleCheckSingleton getInstance(a){
if(lazy==null) {synchronized (LazyDoubleCheckSingleton.class){
if(lazy==null){
lazy=newLazyDoubleCheckSingleton(); }}}returnlazy; }}Copy the code
However, synchronized keyword is always locked, which has a certain impact on program performance. We can also think of class initialization in terms of static inner classes.
public class LazyInnerClassSingleton {
private LazyInnerClassSingleton(a){
if(LazyHolder.LAZY! =null) {throw new RuntimeException("Creating multiple instances is not allowed"); }}public static final LazyInnerClassSingleton getInstance(a){
return LazyHolder.LAZY;
}
private static class LazyHolder{
public static final LazyInnerClassSingleton LAZY = newLazyInnerClassSingleton(); }}Copy the code