立即加载|饿汉模式
什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化。
package multiply.com.test;
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();
}
}
package multiply.com.test;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(MyObject.getInstance().hashCode());
}
}
package multiply.com.test;
public class MyObject {
private static MyObject object = new MyObject();
public static MyObject getInstance() {
return object;
}
}
1213024637
1213024637
1213024637
控制台打印的hashCode是同一个值,说明对象是同一个,也就实现了立即加载型单例设计模式。
延迟加载|懒汉模式
什么是延迟加载?延迟加载就是在调用get()方法时实例才被创建,常见的实现办法就是在get()方法中进行new实例化。
package multiply.com.test;
public class MyObject {
private static MyObject object;
private MyObject()
{
}
public static MyObject getInstance() {
if (null == object) {
try {
Thread.sleep(2000);
object = new MyObject();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return object;
}
}
package multiply.com.test;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(MyObject.getInstance().hashCode());
}
}
package multiply.com.test;
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();
}
}
106990145
355386388
1213024637
控制台打印出了3种hashCode,说明创建出了3个对象,并不是单例的,这就是“错误的单例模式”。
( 1 )声明synchronized关键字
既然多个线程可以同时进入getInstance()方法,那么只需要对getInstance()方法声明synchronized关键字即可。
同步代码块可以针对某些重要的代码进行单独的同步,而其他的代码则不需要同步。
此方法使同步synchronized语句块,只对实例化对象的关键代码进行同步,从语句的结构上来讲,运行的效率的确得到了提升。但如果是遇到多线程的情况下还是无法解决得到同一个实例对象的结果。到底如何解决“懒汉模式”遇到多线程的情况呢?
(4)使用DCL双检查锁机制
在最后的步骤中,使用的是DCL双检查锁机制来实现多线程环境中的延迟加载单例设计模式。
package multiply.com.test;
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();
}
}
package multiply.com.test;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(MyObject.getInstance().hashCode());
}
}
package multiply.com.test;
public class MyObject {
private static volatile MyObject object;
public static MyObject getInstance() {
if (null == object) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (MyObject.class) {
if (null == object) {
object = new MyObject();
}
}
}
return object;
}
}
2042504460
2042504460
2042504460
使用双重检查锁功能,成功地解决了“懒汉模式”遇到多线程的问题。DCL 也是大多数多线程结合单例模式使用的解决方案。
使用静态内置类实现单例模式
package multiply.com.test;
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();
}
}
package multiply.com.test;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(MyObject.getInstance().hashCode());
}
}
package multiply.com.test;
public class MyObject {
private static class MyObjectHandler {
private static MyObject object = new MyObject();
}
public static MyObject getInstance() {
return MyObjectHandler.object;
}
}
1282593964
1282593964
1282593964
序列化与反序列化的单例模式
静态内置类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。