java 关于单例模式的一点思考
2016-04-11 16:08
567 查看
概念:
java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
懒汉单例模式
线程安全的单例模式
饿汉单例模式
枚举类型单例模式
用单元测试来测试下是否能达到单例的效果
输出如下:
主要原理就是通过将类的构造器设置为private,这样确保实例唯一。但是通过反射机制就可以打破这一限制了。测试代码如下:
通过反射的setAccessible可以绕过private限制,好吧,这不是今天讨论的重点。
其次,如果是在并发环境下使用getinstance则可能会带来并发问题。
java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
懒汉单例模式
线程安全的单例模式
饿汉单例模式
枚举类型单例模式
1.懒汉单例模式
package edu.cczu.singleton; /** * 懒汉式单例类.在第一次调用的时候实例化自己 * @author 这是一台电脑 * */ public class SingletonA { private SingletonA() {} private static SingletonA instance=null; public static SingletonA getInstance() { if (instance == null) { instance = new SingletonA(); } return instance; } }
用单元测试来测试下是否能达到单例的效果
@Test public void test1(){ SingletonA singletonA_1 = SingletonA.getInstance(); SingletonA singletonA_2 = SingletonA.getInstance(); if(singletonA_1 == singletonA_2){ System.out.println("相同的实例"); }else{ System.out.println("不同的实例"); } }
输出如下:
主要原理就是通过将类的构造器设置为private,这样确保实例唯一。但是通过反射机制就可以打破这一限制了。测试代码如下:
@Test public void test2() throws Exception{ Class<?> clazz = Class.forName("edu.cczu.singleton.SingletonA"); Constructor<?> constructor = clazz.getDeclaredConstructor(null); System.out.println(constructor); constructor.setAccessible(true); SingletonA singletonA_1 = (SingletonA) constructor.newInstance(null); SingletonA singletonA_2 = (SingletonA) constructor.newInstance(null); if(singletonA_1 == singletonA_2){ System.out.println("相同的实例"); }else{ System.out.println("不同的实例"); } }
通过反射的setAccessible可以绕过private限制,好吧,这不是今天讨论的重点。
其次,如果是在并发环境下使用getinstance则可能会带来并发问题。
2.线程安全的单例模式
解决并发问题,可以采用以下三种写法:package edu.cczu.singleton; /** * 懒汉+加锁 * @author 这是一台电脑 * */ public class SingletonB { private SingletonB() {} private static SingletonB instance=null; /** * 对getInstance加锁,但实际并发中很少会出现需要加锁的情况,所以不常用 * 不推荐 */ public static synchronized SingletonB getInstance1() { if (instance == null) { instance = new SingletonB(); } return instance; } /** * 双重判定加锁,同上,做了优化 */ public static SingletonB getInstance2() { if (instance == null) { synchronized (SingletonB.class) { if (instance == null) { instance = new SingletonB(); } } } return instance; } /** * 静态内部类 * 线程安全,又避免了同步时的性能损耗 * 推荐使用 */ private static class LazyHolder { private static final SingletonB INSTANCE = new SingletonB(); } public static final SingletonB getInstance3() { return LazyHolder.INSTANCE; } }
3.饿汉单例模式
懒汉模式是在类的getInstance()时才初始化实例,所以会带来线程安全问题,但是饿汉采用的是声明时就初始化实例,所以不会存在线程安全问题,取而代之的是会出现资源浪费的问题。package edu.cczu.singleton; public class SingletonC { private SingletonC() {} private static final SingletonC instance = new SingletonC(); //静态工厂方法 public static SingletonC getInstance() { return instance; } }
4.枚举类型单例模式
下面是《effective java》的“奇技淫巧”,采用枚举类型,讲道理,是解决了以上所有的问题,就是…并不常用,可能是引入新规范后大家还在沿用原有的习惯吧。package edu.cczu.singleton; public enum SingletonD { INSTANCE; private String somefield; public String getSomefield() { return somefield; } public void setSomefield(String somefield) { this.somefield = somefield; } private SingletonD(){} }
相关文章推荐
- JavaSe基础(27)-- 字节流
- 使用Spring Security保护web应用安全
- java Reentrant Lock
- hadoop java.lang.Exception: java.lang.RuntimeException: java.lang.NoSuchMethodException: log_analys
- 霍夫曼编码和解码
- [疯狂Java]JDBC:加载数据库驱动、连接数据库
- LeetCode Climbing Stairs JAVA
- 在adt bundle中自带的eclipse中没有NDK设置的解决方法?
- Spring AOP 实现原理与 CGLIB 应用
- 插入排序原理分析及Java实现
- 码农小汪-spring框架学习之5-spring Container Extension Points 容器扩展点
- 选择排序原理分析及Java实现
- java 读取properties
- spring配置文件详解
- eclipse集成的maven插件下载java源码
- JVM内存解析 笔记联想
- LeetCode 137 -Single Number II ( JAVA )
- 冒泡排序原理分析及Java实现
- Java 8 新特性:Lambda 表达式
- JAVA操作mysql数据库