第6章 单例模式与多线程

xiaoxiao2021-02-27  158

第6章 单例模式与多线程

标签: Java多线程编程

《Java多线程编程核心技术》 个人笔记


第6章 单例模式与多线程 立即加载饿汉模式 延迟加载懒汉模式但是在多线程环境下前面延迟加载的代码完全是错误的根本不能实现保持单例的状态 使用静态内置类实现单例模式序列化与反序列化的单例模式实现 使用static代码块实现单例模式 使用enum枚举数据类型实现单例模式完善使用enum枚举实现单例模式


立即加载/“饿汉模式”

立即加载 就是使用类的时候已经将对象创建完毕,常见的实现方法就是直接new实例化,立即加载也称为“饿汉模式” public class MyObject { //非线程安全 private static MyObject myObject = new MyObject(); private MyObject() { } public static MyObject getInstance() { return myObject; } }

延迟加载/“懒汉模式”

延迟加载 就是在调用get()方法时实例才被创建,常见的实例方法就是在get()方法中进行new实例化 public class MyObject { private static MyObject myObject; private MyObject() { } public static MyObject getInstance() { //在多线程环境下,就会出现取出多个实例的情况 if (myObject != null) { } else { myObject = new MyObject(); } return myObject; } }

但是在多线程环境下,前面“延迟加载”的代码完全是错误的,根本不能实现保持单例的状态。

解决方案: 声明synchronized关键字尝试同步代码块针对某些重要的代码进行单独的同步使用DCL双检查锁机制

声明synchronized关键字

public class MyObject { private static MyObject myObject; private MyObject() { } // 设置同步方法效率太低了 // 整个方法被上锁 synchronized public static MyObject getInstance() { try { if (myObject != null) { } else { //模拟在创建对象之前做一些准备性的工作 Thread.sleep(3000); myObject = new MyObject(); } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } } //-----------主函数-------------- 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(); } }

尝试同步代码块

public static MyObject getInstance() { try { // 此种写法等同于: // synchronized public static MyObject getInstance() // 的写法,效率一样很低,全部代码被上锁 synchronized (MyObject.class) { if (myObject != null) { } else { Thread.sleep(3000); myObject = new MyObject(); } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; }

针对某些重要的代码进行单独的同步

public static MyObject getInstance() { try { if (myObject != null) { } else { Thread.sleep(3000); // 虽然效率提升,但是多线程环境下 非线程安全 synchronized (MyObject.class) { myObject = new MyObject(); } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; }

使用DCL双检查锁机制

public class MyObject { private volatile static MyObject myObject; private MyObject() { } // 使用双检测机制来解决问题,既保证了不需要同步代码的异步执行性 //又保证了单例的效果 public static MyObject getInstance() { try { if (myObject != null) { } else { Thread.sleep(3000); synchronized (MyObject.class) { if (myObject == null) { //双重检查 myObject = new MyObject(); } } } } catch (InterruptedException e) { e.printStackTrace(); } return myObject; } // 此版本称为双重检查 double-Check Locking } 使用双重检查锁功能,成功解决了“懒汉模式”遇到多线程的问题。DCL也是大多数多线程结合单例模式使用的解决方案

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

除了DCL,也有其他方法可以解决多线程单例模式的非线程安全问题 public class MyObject { // 内部类方式 private static class MyObjectHandler { private static MyObject myObject = new MyObject(); } private MyObject() { } public static MyObject getInstance() { return MyObjectHandler.myObject; } }

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

静态内置类可以达到线程安全问题,但如果遇到序列化对象,使用默认的方式运行得到的结果还是多例的解决的方法就是在反序列化中使用readResoulve()方法 public class MyObject implements Serializable { private static final long serialVersionUID = 888L; private static class MyObjectHandler { private static final MyObject myObject = new MyObject(); } private MyObject() { } public static MyObject getInstance() { return MyObjectHandler.myObject; } protected Object readResolve() throws ObjectStreamException { //反序列化用 System.out.println("调用了readResolve方法!"); return MyObjectHandler.myObject; } }

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

静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性实现单例模式 public class MyObject { private static MyObject instance = null; private MyObject() { } static { //静态代码块 instance = new MyObject(); } public static MyObject getInstance() { return instance; } }

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

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

public class MyObject { public enum MyEnumSingleton { //enum connectionFactory; private Connection connection; private MyEnumSingleton() { try { System.out.println("创建MyObject对象"); String url = "jdbc:sqlserver://localhost:1079;databaseName=y2"; String username = "sa"; String password = ""; 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 MyEnumSingleton.connectionFactory.getConnection(); } }
转载请注明原文地址: https://www.6miu.com/read-15432.html

最新回复(0)