Java设计模式-单例模式及线程安全问题
单例模式是非常常用的设计模式,他确保了一个类只有一个对象,并且这个对象是自己创建的,外界可以获取使用到这个对象。
单例模式一般有两种:懒汉式,饿汉式(其实还有一种登记式,把创建的对象放在map集合中,有就直接用,没有就创建)
单例模式通过构造方法私有化,外界无法创建对象,下面是两种单例的实现
饿汉式:
package demo_singleton;
public class SingletonHungry {
private static SingletonHungry singletonhunary = new SingletonHungry();
public static SingletonHungry getinstance() {
return singletonhunary;
}
private SingletonHungry() {
}
}
懒汉式:
package demo_singleton;
/*懒汉式的单例模式,有线程安全问题,当多线程访问的时候,会出现多个实例*/
public class SingletonLazy {
private static SingletonLazy instance = null; public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
} private SingletonLazy() { }
}
多线程环境下的测试:
懒汉式测试:
package demo_singleton;
public class TestLary extends Thread{
public static void main(String[] args) {
TestLary t1 = new TestLary();
TestLary t2 = new TestLary();
TestLary t3 = new TestLary();
t1.start();
t2.start();
t3.start();
}
public void run() {
System.out.println(SingletonLazy.getInstance());
}
}
输出结果:
demo_singleton.SingletonLazy@529e3fc2
demo_singleton.SingletonLazy@529e3fc2
demo_singleton.SingletonLazy@136c03ee
通过输出结果可以看到,其实创建了两个对象
饿汉式测试:
package demo_singleton;
public class TestHungry extends Thread {
public static void main(String[] args) {
TestHungry t1 = new TestHungry();
TestHungry t2 = new TestHungry();
TestHungry t3 = new TestHungry();
t1.start();
t2.start();
t3.start();
}
@Override
public void run() {
System.out.println(SingletonHungry.getinstance());
}
}
输出结果:
demo_singleton.SingletonHungry@6d15a113
demo_singleton.SingletonHungry@6d15a113
demo_singleton.SingletonHungry@6d15a113
在多线程下饿汉式没有出现问题
在单线程的环境下,单例可以实现,当在多线程的条件下,懒汉式的单例就会出现线程安全问题,而饿汉式不会出现。饿汉式代码简单所以线程安全,在类加载的时候创建对象,懒汉式不会再在载的时候创建对象,效率高。代码中有判断对象是否存在的代码,所以线程不安全饿汉式不需要关注多线程问题,写法简单,但是有个缺点,就是不管你用或者不用,在类加载的时候他都会创建对象,而懒汉式的特点是延时加载,但是又带来了线程问题。既然这样我们就要解决它
开始解决懒汉式的问题,最开始想到的是同步,加上synchronized关键字:
优化一:
package demo_singleton;
public class SingletonLazy1 {
private static SingletonLazy1 instance1 = null;
public static synchronized SingletonLazy1 getInstance() {
if (instance1 == null) {
instance1 = new SingletonLazy1();
}
return instance1;
}
private SingletonLazy1() {
}
}
优化二:
加入同步块,对代码进行操作
package demo_singleton;
/*加同步块的单例,效率有问题*/ public class SingletonLazy2 {
private static SingletonLazy2 instance2 = null; public static SingletonLazy2 getInstance() {
synchronized (SingletonLazy2.class) {
if (instance2 == null) {
instance2 = new SingletonLazy2();
}
}
return instance2;
} private SingletonLazy2() { }
}
优化三:
package demo_singleton;
public class SingletonLazy3 {
private static SingletonLazy3 instace3 = null;
public static SingletonLazy3 getInstance() {
if (instace3 == null) {
synchronized (SingletonLazy3.class) {
if (instace3 == null) {
instace3 = new SingletonLazy3();
}
}
}
return instace3;
}
private SingletonLazy3() {
}
}
相对于前两个优化,利用同步解决线程问题,第三个利用两个判断,当程序判断对象没有创建的时候进入执行同步代码块,创建对象。在下次判断对象存在的时候,不会再执行同步代码块中的代码,相对于前两个效率会搞一些
优化四:
package demo_singleton;
public class SingletonLazy4 {
private static SingletonLazy4 instance4 = null;
static{
instance4 = new SingletonLazy4();
}
public static SingletonLazy4 getInstance() {
return instance4;
}
private SingletonLazy4() {
}
}
利用static静态代码块的特点,创建对象,static代码块在类加载的时候最开始执行并且只会执行一次
优化五:
package demo_singleton;
public class SingletonLazy5 {
private static class Sing {
private static SingletonLazy5 instance = new SingletonLazy5();
}
public static SingletonLazy5 getInstance() {
return Sing.instance;
}
private SingletonLazy5() {
}
}
利用静态内部类,内部类在编译的时候也是一个单独的class文件,在调用的时候会执行,不调用的时候不会执行
注意:利用Java的反射机制也是可以破坏单例的
参考:http://blog.csdn.net/cselmu9/article/details/51366946
Java设计模式-单例模式及线程安全问题的更多相关文章
- JAVA设计模式-单例模式(Singleton)线程安全与效率
一,前言 单例模式详细大家都已经非常熟悉了,在文章单例模式的八种写法比较中,对单例模式的概念以及使用场景都做了很不错的说明.请在阅读本文之前,阅读一下这篇文章,因为本文就是按照这篇文章中的八种单例模式 ...
- Java设计模式の单例模式
-------------------------------------------------- 目录 1.定义 2.常见的集中单例实现 a.饿汉式,线程安全 但效率比较低 b.单例模式的实现:饱 ...
- 【设计模式】Java设计模式 - 单例模式
[设计模式]Java设计模式 - 单例模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 分享学习心得,欢迎指正,大家一起学习成长! 原创作品,更多关注我CSDN: ...
- java设计模式单例模式 ----懒汉式与饿汉式的区别
常用的五种单例模式实现方式 ——主要: 1.饿汉式(线程安全,调用率高,但是,不能延迟加载.) 2.懒汉式(线程安全,调用效率不高,可以延时加载.) ——其他: 1.双重检测锁式(由于JVM底层内部模 ...
- 并发编程学习笔记(3)----synchronized关键字以及单例模式与线程安全问题
再说synchronized关键字之前,我们首先先小小的了解一个概念-内置锁. 什么是内置锁? 在java中,每个java对象都可以用作synchronized关键字的锁,这些锁就被称为内置锁,每个对 ...
- Java设计模式 - - 单例模式 装饰者模式
Java设计模式 单例模式 装饰者模式 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 静态代理模式:https://www.cnblogs.com/StanleyBlogs/p/1 ...
- Java单例模式的线程安全问题
单例模式有两种书写模式:饿汉式和懒汉式. 1.饿汉式 class Single{ private final static Single s = new Single(); private Singl ...
- java设计模式--解决单例设计模式中懒汉式线程安全问题
首先写个单例,懒汉模式: public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} pu ...
- Java设计模式 - 单例模式 (懒汉方式和饿汉方式)
概念: Java中单例模式是一种常见的设计模式,单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 单例模式的写法有好几种,这 ...
随机推荐
- springmvc报406错误
springmvc出现406,无非就两种情况,第一,百分之九十是json包没加进来,第二,百分之十,就是@ResponseBody返回的的数据,在请求的URL中不能有 .html的后缀
- CentOS7网卡命名规则
CentOS6之前基于传统的命名方式如:eth1,eth0.... Centos7提供了不同的命名规则,默认是基于固件.拓扑.位置信息来分配.这样做的优点是命名是全自动的.可预知的,缺点是比eth0. ...
- mysql数据库相关基本术语和概念
1.DDL:Data Definition Language,即数据定义语言,定义数据库涉及的各种对象,定义数据的完整性约束.保密限制等约束. 2.DML:Data Manipulation Lang ...
- Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 't.statis_date'
1.错误原因 [ERROR:]2015-04-18 13:20:31,883 [异常拦截] com.skycloud.oa.exception.ExceptionHandler org.hiberna ...
- JavaScript通过ID和name设置样式
JavaScript通过ID和name设置样式 1.说明 (1)根据所提供的元素的id值,返回对该元素的引用或节点 document.getElementById("tr_th") ...
- OpenStack_I版 4.Dashboard部署
由python的DjangoWeb框架开发的 使用keystone默认的角色来访问各种服务 Dashboard安装 Dashboard是openstack的Web管理界面,需要将它 ...
- Fu+ 后台管理 (Thinkphp)
简要:小主从事PHP二年,期间一直做后台;为此向大家分享我制作一个后台(权限),希望能够跟各位PHP大神学习探索,如果有不对或者好的建议告知下:*~*! 1. 介绍 Fu+ 后台管理,是本人基于H+好 ...
- 一次SQL慢查询的优化处理
背景 在开发完成,数据验证的过程中,需要对两个非常大的表进行query,运行了十几分钟都跑不完.如下: select * from big_a a, big_b b where a.some_id = ...
- 【BZOJ1911】【APIO2010】特别行动队(斜率优化,动态规划)
[BZOJ1911][APIO2010]特别行动队 题面 Description 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号, 要将他们拆分成若干特别行动队调入战场.出于默契的考 ...
- 剑指offer-(19)顺时针打印矩阵
题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2, ...