• java单例模式


    单例模式:运行期间有且仅有一个实例

    一. 关键点:

    1.一个类只有一个实例------最基本的-----(只提供私有构造器)

    2.该类必须自行创建这个实例-----(定义了静态的该类的私有对象)

    3.该类必须自行向整个系统提供这个实例---(提供一个静态的公有方法,返回创建或者获取本身的静    态私有对象)

    二.基本单例模式

    1.懒汉模式

    懒汉模式:在类加载的时候,不创建实例,运行调用的时候创建(以时间换空间

       优缺点:类加载快,在运行时获取速度慢;线程不安全;

    解决懒汉模式线程安全方法:(1)方法体加同步(2)双重校验锁

    懒汉模式特性:lazy  Loading(延迟加载)    

    2.饿汉模式

    饿汉模式:在类加载的时候就会完成初始化。(以空间换时间

    优缺点:类加载慢,但在运行时获取对象速度快;线程安全

     三.代码展示  

    懒汉模式代码:

    import java.io.IOException;

    import java.io.InputStream;

    import java.util.Properties;

    /**

     * 读取数据库配置文件的工具类--单例模式

     * */

    public class ConfigManager {

    // 01定义静态私有本类对象

    private static ConfigManager configManager;

    private static Properties properties;

    // 02私有化本类构造方法--读取配置文件

    private ConfigManager() {

    // 定义要读取的配置文件

    String configFile = "database.properties";

    properties = new Properties();

    // 以输入流的形式获取配置文件

    /**

     * ConfigManager.class.getClassLoader():获取本类根目录

     * getResourceAsStream(configFile):以流的形式获取配置文件

     * */

    InputStream is = ConfigManager.class.getClassLoader()

    .getResourceAsStream(configFile);

    try {

    // 读取配置文件(把流放入properties对象)

    properties.load(is);

    } catch (IOException e) {

    e.printStackTrace();

    } finally {

    try {

    // 关闭流

    is.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    //03 提供全局访问接口

    /**

     * 懒汉模式:线程不安全,在多线程并发情况下,

     * 可能会创建多个ConfigManager实例

     *

     *

     * 001简单懒汉模式--适合单线程安全

     * public static ConfigManager getInstance() {

    if (configManager == null) {

    configManager = new ConfigManager();

    }

    return configManager;

    }

     * 解决线程安全问题:

     //002.方法体加同步,每一个时间点只允许一个线程通过该方法

    public static  synchronized ConfigManager getInstance() {

    if (configManager == null) {

    configManager = new ConfigManager();

    }

    return configManager;

    }

    // 04获得properties对象的值

    public String getString (String key) {

    return properties.getProperty(key);

    }

     

           饿汉模式代码

     1 import java.io.IOException;
     2 import java.io.InputStream;
     3 import java.util.Properties;
     4 
     5 /**
     6  * 读取数据库配置文件的工具类--单例模式
     7  * */
     8 public class ConfigManager {
     9     // 01定义静态私有本类对象
    10        private static ConfigManager configManager=new ConfigManager();//初始化实例
              private static Properties properties;
    15     // 02私有化本类构造方法--读取配置文件
    16     private ConfigManager() {  
    17         // 定义要读取的配置文件
    18         String configFile = "database.properties";
    19         properties = new Properties();
    20         // 以输入流的形式获取配置文件
    21         /**
    22          * ConfigManager.class.getClassLoader():获取本类根目录
    23          * getResourceAsStream(configFile):以流的形式获取配置文件
    24          * */
    25         InputStream is = ConfigManager.class.getClassLoader()
    26                 .getResourceAsStream(configFile);
    27         try {
    28             // 读取配置文件(把流放入properties对象)
    29             properties.load(is);
    30         } catch (IOException e) {
    31             e.printStackTrace();
    32         } finally {
    33             try {
    34                 // 关闭流
    35                 is.close();
    36             } catch (IOException e) {
    37                 e.printStackTrace();
    38             }
    39         }
    40     }
    41     //03 提供全局访问接口
    42     
    69 /*饿汉模式
    70  * 线程安全:在加载类时创建实例,因为实例是static,
    71  *所以只加载一次
    72  * */
    73     
    74     public static   ConfigManager getInstance(){
    75         return  configManager;
    76     }
    77 
    78 
    79     // 04获得properties对象的值
    80     public String getString (String key) {
    81         return properties.getProperty(key);
    82     }
    83 }

     饿汉模式变种:静态代码块

     public class SingleTon {
     // 饿汉模式变种:静态代码块
          private static SingleTon singleTon = null;
           static {
     //类加载是执行静态代码块,只执行一次
           singleTon = new SingleTon();
          }
    private SingleTon() { }
       public static SingleTon getInstance() {
             return singleTon;
    }
       }
    View Code

    懒汉模式线程安全之双重校验锁

    private static SingleTon singleTon;
     
    private SingleTon() {
    }
     
    public static SingleTon getInstance() {
              if (singleTon == null) {//第一重校验(第一批并发线程以后的线程不会通过这里,因为已经实例化)
                      synchronized (SingleTon.class) {//锁,类同步安全(只允许一批并发线程中的一个线程通过)
                             if (singleTon == null) {//第二重校验(非空判断,实例为空通过,不为空止步)
                                          singleTon = new SingleTon();//校验全部通过,创建实例
                          }
                  }
           }
                     return singleTon;
             }
    }
    View Code

     测试模拟多线程并发与双重锁

    package cn.bdqn.util;
    /**
     * 线程类
     * 模拟多线程并发
     * */
    public class ThreadDemo extends Thread {
    private String threadNo;
    public ThreadDemo() {
    }
    public ThreadDemo(String threadNo) {
    this.threadNo = threadNo;
    }
    public String getThreadNo() {
    return threadNo;
    }
    public void setThreadNo(String threadNo) {
    this.threadNo = threadNo;
    }
     
    @Override
    public void run() {
           super.run();
    //调用单利模式方法,模拟测试双重锁
           System.out.println(threadNo);
           SingleTon.getInstance(threadNo);
         }
    }
    View Code
    package cn.bdqn.util;
    /*
     * 测试类,测试线程双重锁
     *
     * */
    public class ThreadTest {
     
    public static void main(String[] args) {
    for (int i = 0; i < 7; i++) {// 相当于主线程,获取资源之后,瞬间生成n个子线程,相当于并发
                  new ThreadDemo("线程" + i).start();// 创建子线程,并开启
                   if (i == 3) {
                      try {
                             Thread.sleep(1000);//模拟多批线程先后并发
                             System.out.println("sleep*********");
                           } catch (InterruptedException e) {
                                    e.printStackTrace();
                    }
                }
           }
    View Code

    执行结果:

    静态内部类:解决饿汉模式实现lazy loading(延迟加载)

    //创建静态变量
    private static SingleTon singleTon;
    //私有构造
    private SingleTon(){}
    //静态内部类
    private static class SingleTonHelp{
     //创建静态常量,完成实例化
    private static final SingleTon INSTANCE=new SingleTon();
    }
       //提供全局访问的接口
    public static SingleTon  getInstance(){
    return SingleTonHelp.INSTANCE;
    }
      //测试方法
    public static void test(){
    System.out.println("test==============="+singleTon.toString());
    }
    View Code
    package cn.bdqn.util;
    /**
     * 测试静态内部类
     *
     * */
    public class Test02 {
    public static void main(String[] args) {
    System.out.println("SingleTon.getInstance()======="+SingleTon.getInstance().toString());
    //此时test()报空指针异常,因为没有调用静态类方法,没有加载实例,达到延迟加载效果(即在需要时加载创建实例,不会加载类时加载实例)
        SingleTon.test();
    }
    }
    View Code

    什么时候使用单利模式:在比较耗系统性能的时候,比如i/o操作,读取配置文件

    懒汉模式特性:lazy  Loading(延迟加载)

    懒汉模式:以时间换空间

    饿汉模式:以空间换时间(标准饿汉模式为常用模式,不存在线程安全问题)

     

  • 相关阅读:
    抽样调查
    一次项目上线发布的感想
    Nginx failing to load CSS and JS files (MIME type error)
    securecrt-active
    golang-http-post
    remove-weknow-ac from mac chrome
    批量写入redis
    golang 修改数组中结构体对象的值的坑
    golang使用json生成结构体
    json定义
  • 原文地址:https://www.cnblogs.com/liu-chao-feng/p/5971592.html
Copyright © 2020-2023  润新知