文档章节

单例模式与线程安全

 开着坦克的瑞兽
发布于 2017/05/13 21:16
字数 862
阅读 8
收藏 0

概念:

       单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。单例模式主要有饿汉模式和懒汉模式(延迟加载),特点如下:

  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

 

饿汉模式:(在使用类的时候就将类加载,属于线程安全),代码如下

public class Singleton {    
    public static Singleton singleton = new Singleton();
    public Singleton(){}
    public static Singleton getInstance(){
        return singleton;
    }    
    
    public static void main(String[] args) {
        for(int i=0; i<10 ; i++){
            new Thread(new MyRunnable(),"A"+i).start();
        }
    }
}
public class MyRunnable implements Runnable {
     
    @Override
    public void run() {    
      //打印线程名称和返回单例的哈希值
      System.out.println(Thread.currentThread().getName()+" :" +Singleton.getInstance().hashCode());       
         
    }
}

此时打印出来的结果如下(可见取得是同一实例): 

  

 

懒汉模式:(延迟加载,在获取实例的时候,才去创建)

public class Singleton {    
    public static Singleton singleton = null;
    public Singleton(){}
    
    //获取实例时才创建
    public static Singleton getInstance(){    
        if(singleton==null){        
            try {
                //这里暂停1秒钟,模拟创建实例前的初始化工作
                Thread.sleep(1000);
                //创建对象
                singleton = new Singleton();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return singleton;
    }    
    
    public static void main(String[] args) {
        for(int i=0; i<10 ; i++){
            new Thread(new MyRunnable(),"A"+i).start();
        }
    }
}

 

public class MyRunnable implements Runnable {
    
    @Override
    public void run() {        
      //打印线程名称和返回单例的哈希值
      System.out.println(Thread.currentThread().getName()+" :" +Singleton.getInstance().hashCode());        
        
    }
}

此时打印出来的结果如下:(可见其实取得不是同一实例):

 

 对于线程安全问题,一般处理方法就是为该方法加入关键字synchronized( 即:synchronized public static Singleton getInstance(){} ),此时确实能解决线程安全问题,但是,该方法性能不高,于是我这里才有同步代码块的方式,代码如下:

public class Singleton {    
    public static Singleton singleton = null;
    public Singleton(){}
    
    //获取实例时才创建
    public static Singleton getInstance(){    
        if(singleton==null){        
            try {
                //这里暂停1秒钟,模拟创建实例前的初始化工作
                Thread.sleep(1000);
                //创建对象
                synchronized(Singleton.class){
                    singleton = new Singleton();
                }    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return singleton;
    }    
    
    public static void main(String[] args) {
        for(int i=0; i<10 ; i++){
            new Thread(new MyRunnable(),"A"+i).start();
        }
    }
}

但此时还是出现线程不安全的因素,这是因为有可能两个或三个线程同一时间执行到了synchronized(Singleton.class),第一个获取锁的线程new了一个实例,等第一个线程释放锁的时候,第二个线程继续获取锁并从新new一个实例。

想要解决线程安全,只需要采用DCL双锁机制即可,代码如下:

public class Singleton {    
    public static Singleton singleton = null;
    public Singleton(){}
    
    //获取实例时才创建
    public static Singleton getInstance(){    
        if(singleton==null){        
            try {
                //这里暂停1秒钟,模拟创建实例前的初始化工作
                Thread.sleep(1000);
                //创建对象
                synchronized(Singleton.class){
                    if(singleton==null){    
                        singleton = new Singleton();
                    }
                }    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return singleton;
    }    
    
    public static void main(String[] args) {
        for(int i=0; i<10 ; i++){
            new Thread(new MyRunnable(),"A"+i).start();
        }
    }
}

PS:对于不清楚加入同步代码块时,为什么还会出现线程不安全的情况,可留言讨论

© 著作权归作者所有

上一篇: Java动态编译
下一篇: 代理模式
粉丝 0
博文 3
码字总数 3259
作品 0
深圳
私信 提问
设计模式梳理(一)

设计模式梳理(一) 总体来说设计模式分为三大类: @案例源码地址:https://gitlab.com/lxqxsyu/DisgnPattern 创建型模式 简单工厂模式 工厂类是整个模式的关键。它包含必要的判断逻辑,能够...

lxq_xsyu
2017/11/02
0
0
Java单例设计模式的理解与常规实现方式

1:Java中单例模式是一种常见的设计模式,单例模式有以下特点:   单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 2:java中单例模式的写法也有很多种,我在这...

动力节点
01/02
0
0
为什么java中用枚举实现单例模式会更好

枚举单例是java中使用枚举提供一个实例对象来实现单例模式的一种新方法,虽然单例模式在java中早已存在,但枚举单例实际上从java5引入枚举作为它的关键特性之后相对来说还是一个新的概念,这...

zhoujy
2013/06/01
8.8K
1
从实例出发,了解单例模式和静态块

就算你没有用到过其他的设计模式,但是单例模式你肯定接触过,比如,Spring 中 bean 默认就是单例模式的,所有用到这个 bean 的实例其实都是同一个。 单例模式的使用场景 什么是单例模式呢,...

风的姿态
2018/05/29
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
137
0

没有更多内容

加载失败,请刷新页面

加载更多

java通过ServerSocket与Socket实现通信

首先说一下ServerSocket与Socket. 1.ServerSocket ServerSocket是用来监听客户端Socket连接的类,如果没有连接会一直处于等待状态. ServetSocket有三个构造方法: (1) ServerSocket(int port);...

Blueeeeeee
今天
6
0
用 Sphinx 搭建博客时,如何自定义插件?

之前有不少同学看过我的个人博客(http://python-online.cn),也根据我写的教程完成了自己个人站点的搭建。 点此:使用 Python 30分钟 教你快速搭建一个博客 为防有的同学不清楚 Sphinx ,这...

王炳明
昨天
5
0
黑客之道-40本书籍助你快速入门黑客技术免费下载

场景 黑客是一个中文词语,皆源自英文hacker,随着灰鸽子的出现,灰鸽子成为了很多假借黑客名义控制他人电脑的黑客技术,于是出现了“骇客”与"黑客"分家。2012年电影频道节目中心出品的电影...

badaoliumang
昨天
14
0
很遗憾,没有一篇文章能讲清楚线程的生命周期!

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 简介 大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。 ...

彤哥读源码
昨天
15
0
jquery--DOM操作基础

本文转载于:专业的前端网站➭jquery--DOM操作基础 元素的访问 元素属性操作 获取:attr(name);$("#my").attr("src"); 设置:attr(name,value);$("#myImg").attr("src","images/1.jpg"); ......

前端老手
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部