路漫漫其修远兮,吾将上下而求索
单例模式实现
单例,即对象只有一个实例,并且其能够给其他所有对象提供这一实例。同时单例模式有分为懒汉式与饿汉式。懒汉式:当需要对象实例是再创建对象。饿汉式:先创建好对象,需要时直接取用。
分别编码实现:
懒汉式
代码如下:
public class Lazy {
/**
* 构造方法私有化
*/
private Lazy(){
}
private static Lazy lazy;
public static Lazy getInstance(){
if (null == lazy){
lazy = new Lazy();
}
return lazy;
}
public void lazy(){
System.out.println("lazy lazy lazy");
}}
饿汉式
代码如下
public class HungryTest {
/**
* 构造方法私有化 以使该类不能被实例化
*/
private HungryTest(){
}
private static HungryTest hungryTest = new HungryTest();
public static HungryTest getInstance(){
return hungryTest;
}
public void hungry(){
System.out.println("hungry hungry hungry");
}}
测试如下
public static void main(String[] args) {
HungryTest hungryTest = HungryTest.getInstance();
hungryTest.hungry();
System.err.println(hungryTest.toString());
HungryTest hungryTest1 = HungryTest.getInstance();
System.err.println(hungryTest1.toString());
HungryTest hungryTest2 = HungryTest.getInstance();
System.err.println(hungryTest2.toString());
Lazy lazy = Lazy.getInstance();
lazy.lazy();
System.err.println(lazy.toString());
Lazy lazy1 = Lazy.getInstance();
System.err.println(lazy1.toString());
Lazy lazy2 = Lazy.getInstance();
System.err.println(lazy2.toString());
}
以上代码输出结果为:
线程安全问题
通过懒汉式以及饿汉式的代码分析可见在多线程情况下,懒汉式是不符合单一实例的,例如将测试代码改为:
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(3,5,0,
TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
for (int i=0;i<100;i++){
threadPoolExecutor.submit(new Runnable() {
@SneakyThrows
@Override
public void run() {
System.out.println(Lazy.getInstance().toString());
System.err.println(HungryTest.getInstance().toString());
}
});
}
threadPoolExecutor.shutdown();
打印输出结果为:
由于多线程情况下,多线程存在竞争关系,所以导致创建了一个或者多个懒汉式对象实例。将Lazy类的getInstance()方法加锁后即实现了线程安全。但是使用synchronized是耗费性能的一件事情,且饿汉式代码中,在未使用饿汉式对象实例的情况下即对其进行了初始化,加载到了内存当中也是耗费性能的。综上,优化如下:
public static Lazy getInstance() throws InterruptedException {
Thread.sleep(1000L);
synchronized (Lazy.class){
if (null == lazy){
lazy = new Lazy();
}
}
return lazy;
}
OVER