美文网首页
创建型 单例模式(上)(单例初入门)(文末有项目连接)

创建型 单例模式(上)(单例初入门)(文末有项目连接)

作者: _River_ | 来源:发表于2021-05-01 21:09 被阅读0次
    1:什么是单例设计模式
    单例设计模式(Singleton Design Pattern)理解起来非常简单。一个类只允许创建一个对象(或者实例),
    那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。
    
    2:单例模式的应用场景
    处理资源访问冲突
       
    在 UserController 和 OrderController 中,
    我们分别创建两个 Logger 对象。在 Web 容器的 Servlet 多线程环境下,
    如果两个 Servlet 线程同时分别执行 login() 和 create() 两个函数,并且同时写日志到 log.txt 文件中,那就有可能存在日志信息互相覆盖的情况。
    
    @Slf4j
    public class Logger {
        private FileWriter writer;
    
        public Logger() throws IOException {
            File file = new File("A:\\log.txt");
            //true表示追加写入
            writer = new FileWriter(file, true);
        }
    
        public void log(String message) throws IOException {
            log.info("写入数据:{}",message);
            writer.write(message);
            writer.write("\n");
            writer.close();
        }
    }
    
    public class UserController {
        private Logger logger = new Logger();
    
        public UserController() throws IOException {
        }
    
        public void login() throws IOException {
            // ...省略业务逻辑代码...
            logger.log("HSJ  User  logined!");
        }
    }
    
    public class OrderController {
        private Logger logger = new Logger();
    
        public OrderController() throws IOException {
        }
    
        public void create() throws IOException {
            // ...省略业务逻辑代码...
            logger.log("Created an order");
        }
    }
    
    3:尝试添加 synchronized 对象级别 锁解决
    这种锁是一个对象级别的锁,一个对象在不同的线程下同时调用 log() 函数,会被强制要求顺序执行。
    不同的对象之间并不共享同一把锁。
    在不同的线程下,通过不同的对象调用执行 log() 函数,锁并不会起作用,
    
    @Slf4j
    public class Logger {
        private FileWriter writer;
    
        public Logger() throws IOException {
            File file = new File("A:\\log.txt");
            //true表示追加写入
            writer = new FileWriter(file, true);
        }
    
        public void log(String message) throws IOException {
            log.info("写入数据:{}",message);
            //添加this  为对象级别的锁  锁无效
            synchronized (this) {    
                writer.write(message);
            }
            writer.write("\n");
            writer.close();
        }
    }
    
    4:尝试添加 synchronized 类级别 锁解决
    @Slf4j
    public class Logger {
        private FileWriter writer;
    
        public Logger() throws IOException {
            File file = new File("A:\\log.txt");
            //true表示追加写入
            writer = new FileWriter(file, true);
        }
    
        public void log(String message) throws IOException {
            log.info("写入数据:{}",message);
            //添加Logger.class  为类级别的锁  锁生效
            synchronized (Logger.class) {    
                writer.write(message);
            }
            writer.write("\n");
            writer.close();
        }
    }
    
    5:使用单例设计模式解决
    我们将 Logger 设计成一个单例类,程序中只允许创建一个 Logger 对象,
    所有的线程共享使用的这一个 Logger 对象,共享一个 FileWriter 对象,
    同时FileWriter 本身是对象级别线程安全的,也就避免了多线程情况下写日志会互相覆盖的问题。
    
    执行顺序:
    //类加载仅执行一次
    //1:静态常量在类加载时初始化 调用方法new LoggerSingleton()   
    //2:被步骤1调用  执行new LoggerSingleton()   
    //3:在原本方法执行    new LoggerSingleton();
    
    //注意此处final修饰仅表示  LoggerSingleton instance 不可变
    1:private static final LoggerSingleton instance = new LoggerSingleton();
    2:public LoggerSingleton() {}
    3:public LoggerSingleton() {}
    
    //由于getInstance添加了static修饰 因此这里是直接调用getInstance方法
    4: public static LoggerSingleton getInstance() { return instance; }
    5: public static LoggerSingleton getInstance() { return instance; }
    
    @Slf4j
    public class LoggerSingleton {
       
         //static 静态变量                    在类加载时初始化
        //final  变量变常量  只能被赋值一次  在类加载时初始化  
        private static final LoggerSingleton instance = new LoggerSingleton();
        public static LoggerSingleton getInstance() { return instance; }
    
        private FileWriter writer;
    
        public LoggerSingleton() {
            File file = new File("A:\\log.txt");
            //true表示追加写入
            try {
                writer = new FileWriter(file, true);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void log(String message) throws IOException {
            log.info("写入数据:{}", message);
            writer.write(message);
            writer.write("\n");
            writer.close();
        }
    }
    
        
    public class LoggerSingletonDemoStart {    
        public static void main(String[] args) throws IOException {
            //如果没有该 new LoggerSingleton();  则上面第三步去掉  其他一致
            new LoggerSingleton();
    
            //这样就只能获取该单例的Logger对象
            LoggerSingleton.getInstance().log("我是测试单例的Logger啊");     
            LoggerSingleton.getInstance().log("我是测试单例的Logger啊");   
        }
    }
    
    

    项目连接

    请配合项目代码食用效果更佳:
    项目地址:
    https://github.com/hesuijin/hesujin-design-pattern
    Git下载地址:
    https://github.com.cnpmjs.org/hesuijin/hesujin-design-pattern.git
    
    demo-study模块  下 build_design_pattern singleton包下  loggerDemo包

    相关文章

      网友评论

          本文标题:创建型 单例模式(上)(单例初入门)(文末有项目连接)

          本文链接:https://www.haomeiwen.com/subject/tolzrltx.html