设计模式之单例模式
来源:互联网 发布:linux shell 捕获错误 编辑:程序博客网 时间:2024/05/16 09:16
单例模式:确保一个类只有一个实例,并且提供一个全局的访问点。
我们先看一下标准的懒汉方式。
public class SingletonOne {private static SingletonOne Sing; private SingletonOne(){} public static SingletonOne getInstance(){if(Sing==null){Sing=new SingletonOne();}return Sing;}}
分析一下这种写法。
首先声明了一个私有的静态变量
然后我们可以在外部调用
SingletonOne.getInstance()获取对象实例。
但是现在我们模拟一下场景,如果同时两个或者更多线程同时去调用
SingletonOne.getInstance()
会出现什么情况呢,假设线程一先判断完Sing是否为null,这时候JVM把CPU资源切换到了第二个线程,第二个线程去再去判断,发现还是为null,那么将会创建两个不同的对象。如果在确保只有一个线程访问的情况下,这种方式是可以的
我们举个例子:
public class Test {public static void main(String[] args) {for (int i = 0; i < 50; i++) {Thread th=new Thread(new NewSingleton());th.start();}}}class NewSingleton implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubSystem.out.println(SingletonOne.getInstance());}}
这时候我创建了50个线程 同时去调用SingletonOne.getInstance() 我们看一下打印结果。
com.wy.singleton.SingletonOne@22b5ecf4
com.wy.singleton.SingletonOne@2d3375e
com.wy.singleton.SingletonOne@2d3375e
com.wy.singleton.SingletonOne@22b5ecf4
com.wy.singleton.SingletonOne@2d3375e
com.wy.singleton.SingletonOne@2d3375e
com.wy.singleton.SingletonOne@2d3375e
....
这里我只列举几条 我们发现 获取的对象是不一样的。
所以这种方式不适合多线程的情况。
那么有人会说了 使用synchronized 同步方法 或者同步代码块不就可以解决这个问题吗 好 我们实验一下。
我们改动一下getInstance方法
public synchronized static SingletonOne getInstance(){if(Sing==null){Sing=new SingletonOne();}return Sing;}
(在静态方法中使用synchronized ,默认锁为类的类 相当于SingletonOne.class)
然后我们再次运行一下 结果如下
com.wy.singleton.SingletonOne@a2c7b1
com.wy.singleton.SingletonOne@a2c7b1
com.wy.singleton.SingletonOne@a2c7b1
com.wy.singleton.SingletonOne@a2c7b1
com.wy.singleton.SingletonOne@a2c7b1
com.wy.singleton.SingletonOne@a2c7b1
发现这个获取的是一致的。
但是使用synchronized会造成比较耗时,确保只有一个线程进入此方法。 我们同时开启50个线程 那么他会一个个进入。
绝大部分的耗时操作都用在synchronized修饰符的同步准备上,因此从性能上说很不划算。
public class SingletonOne {private static SingletonOne Sing;private SingletonOne(){}public static SingletonOne getInstance(){synchronized (SingletonOne.class) {if(Sing==null){Sing=new SingletonOne();}return Sing;}}}
这种方式与上面那个方式类示 每次调用getInstance()还是要进行同步的。
我们再改一下
public class SingletonOne {private static SingletonOne Sing; private SingletonOne(){}public static SingletonOne getInstance() {if (Sing == null) { synchronized (SingletonOne.class) {//第二个线程会在这里等待锁 第二个线程已经判断Sing==null 那么第二个线程会再次new一次的Sing = new SingletonOne();//假设第一个线程走到这里 }}return Sing;}}
我们再看标准的饿汉方式。
根据JLS(Java Language Specification)中的规定 ,一个类在一个ClassLoader中只会被初始化一次,这点是JVM本身保证的,那就把初始化实例的事情扔给JVM好了,代码被改成这样:也就是标准的饿汉式写法
public class SingletonOne {private static SingletonOne Sing=new SingletonOne();; private SingletonOne(){}public static SingletonOne getInstance() {return Sing;}}
public class SingletonOne {private static class SingleHolder{static final SingletonOne sing=new SingletonOne();}private SingletonOne(){}public static SingletonOne getInstance(){return SingleHolder.sing;}}
这两种方式都是标准的线程安全的写法。
- 设计模式之 单例设计模式
- 设计模式之 单例设计模式
- 设计模式之单例设计模式
- 设计模式之-----------单例设计模式
- 设计模式之:单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之-单例设计模式
- 设计模式之单例设计模式 标签: 设计模式
- 设计模式之单例
- 设计模式之单例
- 设计模式之 单例
- 07-2. A+B和C (15)
- leetcode Distinct Subsequences
- MeasureSpec介绍及使用详解 ViewGroup.getChildMeasureSpec(0,0,0)
- 以此纪念开通博客
- Android_Fragment 学习进阶(一)
- 设计模式之单例模式
- 机房收费 1框架
- ubuntu 12.04安装ibus 中文输入发
- 2014阿里巴巴校园招聘数据分析师职位笔试题目(答案版)
- Hibernate缓存
- android使用MediaPlayer播放音频
- JSP页面图片路径为中文时乱码解决办法
- 【拓扑排序】 HDOJ 3342 Legal or Not
- 使用easyui在ie浏览器下,treegrid,datagrid加载数据很慢,ie浏览器卡住原因