单例模式

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


posted @ 2017-03-22 21:31  水底的土豆  阅读(169)  评论(0编辑  收藏  举报