谈到单例模式,我们立马会想到饿汉式和懒汉式加载,所谓饿汉式就是在创建类时就创建好了实例,懒汉式在获取实例时才去创建实例,即延迟加载。

饿汉式:

Java代码  
 1 package com.bijian.study;2 3 public class Singleton {4 5     private static Singleton instance = new Singleton();6 7     public static synchronized Singleton getInstance() {13 return instance; 14  } 15 }

懒汉式:

Java代码  
 1 package com.bijian.study;
 2
 3 public class Singleton {
 4
 5     private static Singleton instance = null;
 6
 7     public static synchronized Singleton getInstance() {
 8
 9         // 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     
10         // 使用时生成实例,提高了效率!
11         if (instance == null)
12             instance = new Singleton();
13         return instance;
14     }
15 }

上面第二中形式的lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。

注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。一般认为第一种形式要更加安全些。

对于上面的懒汉式方式,从多线程角度来看,Synchronized放到方法上会影响性能。于是我们不难想到将其放到方法里。

Java代码  
public class Singleton {private static Singleton instance = null;private static String lock = "";public static Singleton getInstance() {if (instance == null)synchronized (lock) {instance = new Singleton();}return instance;}
}

我们稍加分析,不难发现,这样会存在线程安全问题,假如线程一刚好执行完if (instance == null)的判断语句(还未加锁),调度至线程二也执行这条判断语句,也是true,也进入了if的语句块中,这样就会产生两个实例,而非单实例了。

此时,我们稍加分析,那还不容易,在锁里面再加一个是否为空的判断,即所谓的double-checked locking (DCL),如下所示:

Java代码  
package com.bijian.study;public class Singleton {private static Singleton instance = null;private static String lock = new String();public static Singleton getInstance() {// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     // 使用时生成实例,提高了效率!if (instance == null)synchronized(lock) {if (instance == null) {instance = new Singleton();}}return instance;}
}

此时,很多人都会觉得无懈可击了。从多线程角度来看,这样写的单例确实没有问题了,但从Java的类创建原理来看,可能还有问题。从浅显简单的理解来看,就是对象还未完全创建出来,但instance变量已被赋值,此时另一个线程获取实例时,会得到instance,但它的堆空间及相关的方法还未完成时,调用实例方法就会出错。

啊?还存在这样的问题呀?这可以虚拟机的实现问题,难道还要我考虑?是的,其实稍加改动,就可以避免这样的问题。

解决办法,加一个局部变量,如下所示:

Java代码  
package com.bijian.study;public class Singleton {private static Singleton instance = null;private static String lock = new String();public static Singleton getInstance() {// 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     // 使用时生成实例,提高了效率!if (instance == null)synchronized(lock) {if (instance == null) {Singleton temp = new Singleton();instance = temp;}}return instance;}
}

转载于:https://www.cnblogs.com/fengjian/p/4345686.html

单例模式中的多线程分析synchronized相关推荐

  1. 【深入设计模式】单例模式—从源码分析内部类单例、枚举单例以及单例模式在框架中的应用

    文章目录 1. 使用静态内部类实现单例模式 1.1 静态内部类单例写法 1.2 如何实现懒加载 1.3 为什么线程安全 2. 枚举类型单例单例模式 2.1 枚举类型单例写法 2.2 枚举类型单例原理 ...

  2. 线程的同步之Synchronized在单例模式中的应用

    synchronized在单例模式中的使用 在单例模式中有一种懒汉式的单例,就是类初始化的时候不创建对象.等第一次获取的时候再创建对象.这种单例在单线程下是没有问题的获取的也都是同一个对象.但是如果放 ...

  3. Java多线程中使用ReentrantLock、synchronized加锁 简单举例

    Java多线程中使用ReentrantLock.synchronized加锁 简单举例 public class Demo {final static Lock lock = new Reentran ...

  4. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多线程分析之一:使 ...

  5. JUC多线程:synchronized锁机制原理 与 Lock锁机制

    前言: 线程安全是并发编程中的重要关注点,造成线程安全问题的主要原因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据.因此为了解决这个问题,我们可能需要这样一个方案,当存在多 ...

  6. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 在前文<Android多线程分 ...

  7. Dalvik/ART(ANDROID)中的多线程机制(3)

    封装任务 Message 在整个消息处理机制中,message又叫task,封装了任务携带的信息和处理该任务的handler.message的用法比较简单,这里不做总结了.但是有这么几点需要注意(待补 ...

  8. java中的多线程有什么意义_Java多线程与并发面试题(小结)

    1,什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线程完成一 ...

  9. java怎样获取线程的进度_java中的多线程——进度2

    多线程总结: 1,进程和线程的概念. |--进程:是一块包含了某些资源的内存区域.操作系统利用进程把它的工作划分为一些功能单元: 最小的内存单元: 是具有一定独立功能的程序关于某个数据集合上的一次运行 ...

最新文章

  1. linux查看ssh端口8222,下载服务器SSH被用户恶意猜密码了
  2. java正则表达式:查找所有{XXX}
  3. 基本ACL与高级ACL
  4. php 自动列,设置自动调整列phpExcel
  5. 《.NET设计规范 约定、惯用法与模式》读书笔记
  6. Web 高效开发必备的 PHP 框架
  7. Android官方开发文档Training系列课程中文版:后台加载数据之处理CursorLoader的查询结果
  8. kl散度度量分布_数据挖掘比赛技巧——确定数据同分布
  9. Python面试常用的高级用法,怎么动态创建类?
  10. 小学音乐教学和计算机的融合,小学学科教学与计算机深度融合赛课心得体会(共4篇)...
  11. python官网中文官网-Python官方中文文档强势来袭
  12. 在Ubuntu中配置SSH(解决connect to host localhost port 22: Connection refused问题)
  13. MySql 5.7 Archive 版本安装失败 解决过程
  14. [原创]集成了网络/加密解密/大数运算/位运算等功能的dll
  15. 计算机网络波特率定义,传输速率——比特率和波特率
  16. iPhone开发阶段性总结
  17. [转载]教师节献礼-关于大学的一点思考
  18. 计算机无法从硬盘启动怎么办,电脑开机无法引导硬盘启动怎么解决
  19. 用户体验设计师、UI 设计师和交互设计师有什么区别?
  20. 计算机制作幻灯片视频教程,如何在电脑上制作幻灯片?

热门文章

  1. 2.C++深入理解 面向对象部分1
  2. ercharts一个页面能放几个_Django的页面模版提取(三)
  3. cent mysql 配置,centos下MySQL安装配置
  4. python︱批量操作文件(os)、图片操作技巧(下载网络图片、skimage.io)
  5. EL表达式用法---查询博客
  6. python算法-冒泡排序
  7. 使用Python定制词云
  8. css补充、JavaScript、Dom
  9. 这么多年被第三方接入坑的那些事。。。关于md5签名和sha1证书的坑
  10. WPF几个核心类的类层次结构