码迷,mamicode.com
首页 > 编程语言 > 详细

Java多线程编程6--单例模式与多线程--使用静态内置类、(反)序列化、static代码块、enum枚举数据类实现

时间:2016-05-12 21:02:23      阅读:409      评论:0      收藏:0      [点我收藏+]

标签:

    前面讲的用DCL可以解决多线程单例模式的非线程安全,虽然看下去十分完美,但还是有一些问题,具体分析看这篇:http://blog.csdn.net/ochangwen/article/details/51348078

    当然用其他的办法也能达到同样的效果。

1、使用静态内置类实现单例模式

public class Singleton {
    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }

    /* 此处使用一个内部类来维护单例 */
    private static class SingletonFactory {
        private static Singleton instance = new Singleton();
    }

    /* 获取实例 */
    public static Singleton getInstance() {
        return SingletonFactory.instance;
    }
}
自定义线程
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Singleton.getInstance().hashCode());
    }
}
public class Run {
    public static void main(String[] args) throws ParseException {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
    }
}
1756075494
1756075494
1756075494

2、序列化与反序列化的单例模式实现

    静态内置类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的。

public class Singleton implements Serializable{
    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }

    /* 此处使用一个内部类来维护单例 */
    private static class SingletonFactory {
        private static Singleton instance = new Singleton();
    }

    /* 获取实例 */
    public static Singleton getInstance() {
        return SingletonFactory.instance;
    }

    /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
    protected Object readResolve() throws ObjectStreamException{
        System.out.println("调用了readResolve方法");
        return getInstance();
    }
}
创建业务类SaveAndRead,代码如下:
public class SaveAndRead {
    public static void main(String[] args)  {
        try {
            Singleton singleton = Singleton.getInstance();
            FileOutputStream fosRef = new FileOutputStream(new File("mySingletonFIle.txt"));
            ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
            oosRef.writeObject(singleton);

            oosRef.close();
            fosRef.close();
            System.out.println(singleton.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try{
            FileInputStream fisRef = new FileInputStream(new File("mySingletonFIle.txt"));
            ObjectInputStream iosRef = new ObjectInputStream(fisRef);
            Singleton singleton = (Singleton) iosRef.readObject();
            iosRef.close();
            fisRef.close();
            System.out.println(singleton.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
723635264
调用了readResolve方法
723635264
如果把Singleton类里的readResolve方法注释掉,则结果会是这样的
1484511730
588729095
不是同一个对象

----------------------------------------------------------------------------------------------------

3、使用static代码块实现单例模式

    静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性来实现单例设计模式。

public class Singleton {
    /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
    private static Singleton instance = null;

    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }

    static {
        instance = new Singleton();
    }

    public static Singleton getInstance() {
        return instance;
    }
}
自定义线程MyThread和Run类不变,结果如下:
1032010069
1032010069
1032010069

4、使用enum枚举数据类型实现单例模式

    枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,也可以应用其这个特性实现单例设计模式,最经典的就是数据库连接。

public enum Singleton {
    connectionFactory;
    private Connection connection;

    private Singleton() {
        try {
            System.out.print("调用了Singleton的构造!");
            String url = "jdbc:sqlserver://localhost:1079;databaseNme=DB";
            String username = "123456";
            String password = "123456";
            String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
            Class.forName(driverName);
            connection = DriverManager.getConnection(url, username,password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public Connection getConnection() {
        return connection;
    }
}
自定义线程里的run方法修改为:
    public void run() {
        System.out.println(Singleton.connectionFactory.
                getConnection().hashCode());
    }
1032010069
1032010069
1032010069

5、完善使用enum枚举实现单例模式

    前面一节将枚举类进行暴露,违反了“职责单一原则”,下面进行完善。

public class Singleton {
    public enum MySingleton {
        connectionFactory;
        private Connection connection;

        private MySingleton() {
            try {
                System.out.print("调用了Singleton的构造!");
                String url = "jdbc:sqlserver://localhost:1079;databaseNme=DB";
                String username = "123456";
                String password = "123456";
                String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
                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 MySingleton.connectionFactory.getConnection();
    }
}

Java多线程编程6--单例模式与多线程--使用静态内置类、(反)序列化、static代码块、enum枚举数据类实现

标签:

原文地址:http://blog.csdn.net/ochangwen/article/details/51351470

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!