1、立即加载/"饿汉模式"
立即加载:使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化,在调用方法前,实例已经被创建了。
package com.threadTest.pattern.singleton; /** * Created by sky on 2017/3/22. */ public class MyObject { //立即加载方式==饿汉模式 private static MyObject myObject = new MyObject(); private MyObject() { } public static MyObject getInstance() { //代码版本为立即加载 //此版本代码的缺点是不能有其他实例变量 //因为getInstance()方法没有同步,所以有可能出现非线程安全问题 return myObject; } }
package com.threadTest.pattern.singleton; /** * Created by sky on 2017/3/22. */ public class MyThread extends Thread{ @Override public void run() { System.out.println(MyObject.getInstance().hashCode()); } }
package com.threadTest.pattern.singleton; /** * Created by sky on 2017/3/22. */ 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(); } }
输出:
535693062
535693062
535693062
2、延迟加载/"懒汉模式"
延迟加载:调用get()方法时实例才被创建,常见的实现办法就是在get()方法中进行new实例化。
package com.threadTest.pattern.singleton.lazyman; /** * Created by sky on 2017/3/22. */ public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { //延迟加载 if (null != myObject) { } else { myObject = new MyObject(); } return myObject; } }
延迟加载/"懒汉模式"的缺点:
package com.threadTest.pattern.singleton.lazyman03; /** * Created by sky on 2017/3/22. */ public class MyObject { private static MyObject myObject; private MyObject() { } //效率低下 synchronized public static MyObject getInstance() { //延迟加载 if (null != myObject) { } else { try { //模拟在创建对象之前做一些准备性工作 导致阻塞 Thread.sleep(3000); myObject = new MyObject(); } catch (InterruptedException e) { e.printStackTrace(); } } return myObject; } }
使用DCL双检查锁机制
package com.threadTest.pattern.singleton.lazyman05; /** * Created by sky on 2017/3/22. */ public class MyObject { private static MyObject myObject; private MyObject() { } //效率低下 public static MyObject getInstance() { try { //使用双检测机制来解决, 既保证了不需要同步代码的异步执行性,又保证了单例的效果 if (null != myObject) { } else { //模拟在创建对象之前做一些准备性工作 导致阻塞 Thread.sleep(3000); synchronized (MyObject.class) { if (null == myObject) { myObject = new MyObject(); } } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } }
3、使用静态内置类实现单例模式
package com.threadTest.pattern.singleton.test01; /** * Created by sky on 2017/3/22. */ public class MyObject { //内部类方式 private static class MyObjectHandler { private static MyObject myObject = new MyObject(); } private MyObject(){} public static MyObject getInstance(){ return MyObjectHandler.myObject; } }
4、序列化和反序列化单例模式
package com.threadTest.pattern.singleton.serialize; import java.io.ObjectStreamException; import java.io.Serializable; /** * Created by sky on 2017/3/22. */ public class MyObject implements Serializable { private static final long serialVersionUID = 800L; //内部类方式 private static class MyObjectHandler { private static MyObject myObject = new MyObject(); } private MyObject() { } public static MyObject getInstance() { return MyObjectHandler.myObject; } //方法readResolve会在ObjectInputStream已经读取一个对象并在准备返回前调用。 // ObjectInputStream 会检查对象的class是否定义了readResolve方法。 // 如果定义了,将由readResolve方法指定返回的对象。 // 返回对象的类型一定要是兼容的,否则会抛出ClassCastException 。 protected Object readResolve() throws ObjectStreamException { System.out.println("调用了 readResolve方法!"); return MyObjectHandler.myObject; } }
package com.threadTest.pattern.singleton.serialize; import java.io.*; /** * Created by sky on 2017/3/22. */ public class SaveAndRead { public static void main(String[] args) { try { MyObject myObject = MyObject.getInstance(); FileOutputStream fosRef = new FileOutputStream(new File("F:/myObjectFile.txt")); ObjectOutputStream oosRef = new ObjectOutputStream(fosRef); oosRef.writeObject(myObject); oosRef.close(); fosRef.close(); System.out.println(myObject.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { FileInputStream fisRef = new FileInputStream(new File("F:/myObjectFile.txt")); ObjectInputStream iosRef = new ObjectInputStream(fisRef); //注意myObject 新建的 MyObject myObject = (MyObject) iosRef.readObject(); iosRef.close(); fisRef.close(); System.out.println(myObject.hashCode()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
输出:
787604730
调用了 readResolve方法!
787604730
5、使用静态代码块实现单例模式
package com.threadTest.pattern.singleton.static01; /** * Created by sky on 2017/3/22. */ public class MyObject { private static MyObject instance = null; private MyObject() {} //静态代码块中的代码在使用类的时候已经执行了 static { instance = new MyObject(); } public static MyObject getInstance() { return instance; } }
6、使用enum枚举类型实现单例模式枚举enum和静态代码块的特性相似,在使用枚举时,构造方法会被自动调用
package com.threadTest.pattern.singleton.enum01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* Created by sky on 2017/3/22.
*/
public class MyObject {
public enum MyEnumSingleton {
connectionFactory;
private Connection connection;
private MyEnumSingleton() {
System.out.println("在使用枚举时,构造方法会被自动调用,调用了MyObject的构造");
String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
String username = "root";
String password = "yuantu123";
String driverName = "com.mysql.cj.jdbc.Driver";
try {
Class.forName(driverName);
connection = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getConnection() {
return connection;
}
}
public static Connection getConnection() {
return MyEnumSingleton.connectionFactory.getConnection();
}
}
package com.threadTest.pattern.singleton.enum01;
/**
* Created by sky on 2017/3/22.
*/
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(MyObject.getConnection().hashCode());
}
}
}
输出:
调用了MyObject的构造
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
9507302
,