单例模式中的多线程分析synchronized
谈到单例模式,我们立马会想到饿汉式和懒汉式加载,所谓饿汉式就是在创建类时就创建好了实例,懒汉式在获取实例时才去创建实例,即延迟加载。
饿汉式:
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 }
懒汉式:
package com.bijian.study; public class Singleton { private static Singleton instance = null; public static synchronized Singleton getInstance() { // 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
// 使用时生成实例,提高了效率!
if (instance == null)
instance = new Singleton();
return instance;
}
}
上面第二中形式的lazy initialization,也就是说第一次调用时初始Singleton,以后就不用再生成了。
注意到lazy initialization形式中的synchronized,这个synchronized很重要,如果没有synchronized,那么使用getInstance()是有可能得到多个Singleton实例。一般认为第一种形式要更加安全些。
对于上面的懒汉式方式,从多线程角度来看,Synchronized放到方法上会影响性能。于是我们不难想到将其放到方法里。
我们稍加分析,不难发现,这样会存在线程安全问题,假如线程一刚好执行完if (instance == null)的判断语句(还未加锁),调度至线程二也执行这条判断语句,也是true,也进入了if的语句块中,这样就会产生两个实例,而非单实例了。
此时,我们稍加分析,那还不容易,在锁里面再加一个是否为空的判断,即所谓的double-checked locking (DCL),如下所示:
此时,很多人都会觉得无懈可击了。从多线程角度来看,这样写的单例确实没有问题了,但从Java的类创建原理来看,可能还有问题。从浅显简单的理解来看,就是对象还未完全创建出来,但instance变量已被赋值,此时另一个线程获取实例时,会得到instance,但它的堆空间及相关的方法还未完成时,调用实例方法就会出错。
啊?还存在这样的问题呀?这可以虚拟机的实现问题,难道还要我考虑?是的,其实稍加改动,就可以避免这样的问题。
解决办法,加一个局部变量,如下所示:
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;
}
}
单例模式中的多线程分析synchronized的更多相关文章
- 线程的同步之Synchronized在单例模式中的应用
synchronized在单例模式中的使用 在单例模式中有一种懒汉式的单例,就是类初始化的时候不创建对象.等第一次获取的时候再创建对象.这种单例在单线程下是没有问题的获取的也都是同一个对象.但是如果放 ...
- 详细分析 Java 中实现多线程的方法有几种?(从本质上出发)
详细分析 Java 中实现多线程的方法有几种?(从本质上出发) 正确的说法(从本质上出发) 实现多线程的官方正确方法: 2 种. Oracle 官网的文档说明 方法小结 方法一: 实现 Runnabl ...
- Android多线程分析之四:MessageQueue的实现
Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...
- Android多线程分析之三:Handler,Looper的实现
Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...
- Android多线程分析之二:Thread的实现
Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多线程分析之一 ...
- Android四个多线程分析:MessageQueue实现
Android四个多线程分析:MessageQueue的实现 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 在前面两篇文章<Android多线 ...
- OS X 和iOS 中的多线程技术(上)
OS X 和iOS 中的多线程技术(上) 本文梳理了OS X 和iOS 系统中提供的多线程技术.并且对这些技术的使用给出了一些实用的建议. 多线程的目的:通过并发执行提高 CPU 的使用效率,进而提供 ...
- Apollo配置中心源码分析
Apollo配置中心源码分析 1. apollo的核心代码分享 SpringApplication启动的关键步骤 在SpringApplication中,会加载所有实现了Init方法的类 protec ...
- java 多线程8 : synchronized锁机制 之 方法锁
脏读 一个常见的概念.在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数 ...
随机推荐
- Nginx 支持 CI 框架的配置并禁止使用 ip 访问
#CIserver { listen 80; server_name www.ci.com; index index.php index ...
- 【转】request和response的页面跳转传参
下面是一位园友的文章: jsp或Servlet都会用到页面跳转,可以用 request.getRequestDispatcher("p3.jsp").forward(request ...
- JVM-字节码执行引擎
虚拟机字节码执行引擎 一.运行时栈帧结构 1.栈帧(Stack Frame)是用于支持虚拟机进行调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Method Stack) ...
- MAC机中安装ruby环境--转载
http://www.cnblogs.com/pingfan1990/p/4957162.html
- HDU1016 dfs
刷回溯的时候发现我对DFS思路很不清晰,总是做着做着就乱了,刷个水题找找思路. 题意:经典DFS,找出所有的能让1~n的数形成素数环的序列(相邻相加为素数): #include <iostrea ...
- 北京网赛I题 hiho1391 (树状数组、区间覆盖最大值问题)
题目链接:http://hihocoder.com/problemset/problem/1391 题意:A国和B国向对方分别投射N枚和M枚导弹(发射时间,飞行时间,伤害值),同时两国各自都有防御系统 ...
- Unity UGUI RectTransform图解
UGUI RectTransform.Unity RectTransform详解 The first:look look API. http://docs.unity3d.com/ScriptRefe ...
- 根据地图上的两个点各自的x,y坐标,计算出2点之间的直线距离。显示为公里、米
/** * calc_map_distance() , 根据地图上的两个点各自的x,y坐标,计算出2点之间的直线距离 * @param array $point_1 第1个点的x,y坐标 array( ...
- 第三个Sprint冲刺第三天
讨论地点:宿舍 讨论成员:邵家文.李新.朱浩龙.陈俊金 讨论问题:增强了界面的效果,改善了视角
- ps esc 问题
最近经常发现esc键突然变得不能用了.主要是使用搜狗输入法时使用esc键取输错的字,因此还以为是搜狗的问题,后来突然想到可能是因为打开某个软件导致esc不能用,最后发现居然是ps,在网上查了后发现很多 ...