1.立即加载/饿汉模式
package singleton;
public class MyThread extends Thread{
@Override
public void run() {
System.out.println(MyObject.getInstance().hashCode());
}
}
package singleton;
public class MyObject {
private static MyObject myObject = new MyObject();
public static MyObject getInstance(){
return myObject;
}
}
package singleton;
public class Run {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();
t2.start();
t3.start();
}
}
运行结果皆为:
11077203
2.延迟加载/懒汉模式
package singleton;
public class MyObject2 {
private static MyObject2 myObject;public static MyObject2 getInstance() {
try {
if (myObject == null) {
Thread.sleep(3000);//模拟在创建对象前做一些准备工作
myObject = new MyObject2();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return myObject;
}
}
在多线程中,就会出现取出多个实例的情况,与单例模式的初衷是相背离的。运行结果为:
11077203
14576877
12677476
3.懒汉模式的改进方法
3.1 整个getInstance()方法声明synchronized关键字 ,但是效率太低。
3.2 在getInstance()方法里声明MyObject.class的synchronized同步语句块,其实相当于全部代码被上锁,效率依旧很低。
3.3 在某些重要的代码实施同步语句块,
package singleton;
public class MyObject3 {
private static MyObject3 myObject;public static MyObject3 getInstance() {
try {
if (myObject == null) {
Thread.sleep(3000);
synchronized(MyObject3.class){
myObject = new MyObject3();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return myObject;
}
}
虽然大大提高效率,但是非线程安全,无效。
3.4 使用DCL双检查锁机制 -- 推荐
package singleton;
public class MyObject4 {
private volatile static MyObject4 myObject;public static MyObject4 getInstance() {
try {
synchronized (MyObject4.class) {
if (myObject == null) {
Thread.sleep(3000);
myObject = new MyObject4();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return myObject;
}
}
3.5 静态内部类方式
package singleton;
public class MyObject5 {
private static class MyObjectHandler {
private static MyObject5 myObject = new MyObject5();
}public static MyObject5 getInstance() {
return MyObjectHandler.myObject;
}
}
3.6 序列化与反序列化解决:在反序列化中使用readResolve()方法(略)。
3.7 使用static代码块实现:
package singleton;
public class MyObject6 {
private static MyObject6 instance = null;static {
instance = new MyObject6();
}public static MyObject6 getInstance() {
return instance;
}
}
3.8 使用枚举数据类型enum:
使用枚举类时,构造方法会被自动调用。(但不要将枚举类进行曝露,应将枚举类包装在一个正常类中,遵守职责单一原则)