饿汉式:
package com.xyz.bean;
/**
* 饿汉式单例设计模式
* 私有化静态final 属性
* 私有化构造
* 提供public static 的genInstance方法
*/
public class Singleton1 {
private static final Singleton1 singleton1 = new Singleton1();
private Singleton1(){
}
public static Singleton1 getInstance(){
return singleton1;
}
}
懒汉式(不加锁):
package com.xyz.bean;
/**
* 懒汉式单例
* 提供私有的对象 并开始置空
* 在调用时初始化
*/
public class Singleton2 {
private static Singleton2 singleton2 = null;
private Singleton2(){
}
public static Singleton2 getInstance(){
if(singleton2==null){
return new Singleton2();
}
return singleton2;
}
}
懒汉式可能会出现的问题,使用多线程进行测试。
package test;
import com.xyz.bean.Singleton1;
import com.xyz.bean.Singleton2;
import org.junit.Test;
public class TestSingleton extends Thread {
private static Singleton2 singleton2 = null;
@Override
public void run() {
this.singleton2 = Singleton2.getInstance();
System.out.println(this.singleton2+":"+singleton2.getClass());
}
@Test
public void getSingleton(){
//继承Thread类 重写run方法
Thread ts = new TestSingleton();
//启动线程
ts.start();
singleton2 = Singleton2.getInstance();
System.out.println(singleton2+":"+singleton2.getClass());
//使用匿名内部类实现多线程
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
Singleton1 singleton1 = Singleton1.getInstance();
System.out.println(singleton1+":"+singleton1.getClass());
}
});
thread1.start();
//实现Runnable 接口 重写run方法
Runnable runnable = new Runnable() {
@Override
public void run() {
Singleton1 singleton1 = Singleton1.getInstance();
System.out.println(singleton1+":"+singleton1.getClass());
}
};
new Thread(runnable).start();
}
}
/**运行结果:
* com.xyz.bean.Singleton2@593634ad:class com.xyz.bean.Singleton2
* com.xyz.bean.Singleton2@52b59e9c:class com.xyz.bean.Singleton2
* com.xyz.bean.Singleton1@c87cc8f:class com.xyz.bean.Singleton1
* com.xyz.bean.Singleton1@c87cc8f:class com.xyz.bean.Singleton1
* */
可以看出,不加锁的懒汉式,再遇到多线程时,会产生两个不一样的引用。为此,给它上锁!
package com.xyz.bean;
public class Singleton3 {
private static Singleton3 singleton3 = null;
private Singleton3(){
}
//给Singleton3 加上类级锁
public static synchronized Singleton3 getInstance(){
if(singleton3 == null){
singleton3 = new Singleton3();
}
return singleton3;
}
}
然后在TestSingleton加上如下测试:
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
Singleton3 singleton3 = Singleton3.getInstance();
System.out.println(singleton3+":"+this.getClass());
}
});
thread2.start();
System.out.println(Singleton3.getInstance()+":"+this.getClass());
测试通过,两者获得的引用一致!
总结:
1.饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,不管创建多少个实例对象,永远都只分配了一个static变量,缺点是会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。
2.懒汉式是非线程安全的,可以使用同步锁synchronized,好处是可以延迟加载。另外也可以使用静态内部类来实现锁的功能。
如:
public class Singleton {
private static class Init {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return Init.INSTANCE;
}
}