码迷,mamicode.com
首页 > 编程语言 > 详细

设计模式——单例模式(Java)——考虑多线程环境下的线程安全问题

时间:2016-05-12 17:41:36      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:

设计模式——单例模式(Java)——考虑多线程环境下的线程安全问题

一:单例模式概念

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例

二:单例模式的实现方式

特别注意,在多线程环境下,需要对获取对象实例的方法加对象锁(synchronized)

方式一:(懒汉式)程序执行过程中需要这个类的对象,再实例化这个类的对象

步骤:

1.定义静态私有对象

2.构造方法私有化保证在类的外部无法实例化该类的对象

3.定义对外开放的静态方法在调用方法时判断对象是否为空,为空再创建对象返回

public class Singleton{
//1.定义静态私有对象
priavate static Singleton singleton;
//2.构造方法私有化,保证在类的外部无法实例化该类的对象
private Singleton(){
}
//3.定义对外开放的静态方法在调用方法是判断对象是否为空,为空再创建对象返回
public static synchronized Singleton getSingletonInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}

方式二:(饿汉式)类加载的时候就实例化该类的对象

步骤:

1.定义静态私有对象,并实例化

2.构造方法私有化保证在类的外部无法实例化该类的对象

3.定义对外开放的静态方法

public class Singleton{
//1.定义静态私有对象,并实例化
priavate static Singleton singleton=new Singleton();
//2.构造方法私有化,保证在类的外部无法实例化该类的对象
private Singleton(){
}
//3.定义对外开放的静态方法
public static synchronized Singleton getSingletonInstance(){
return singleton;
}
}

三:在多线程情况下,单例对象的同步问题

1.单例对象的初始化

1.1问题引入:

在多线程情况下,如果第一个线程发现对象为空,准备创建;这时第二个线程同时也发现对象为空,也会创建。这样就会造成在一个JVM中有多个单例类型的实例。

1.2问题解决:(对象的创建加同步锁sychronized)


 1 //单例对象的初始化同步
 2 public class GlobalConfig {
 3     private static GlobalConfig instance = null;
 4     private Vector properties = null;
 5     private GlobalConfig() {
 6       //Load configuration information from DB or file
 7       //Set values for properties
 8     }
 9     private static synchronized void syncInit() {
10       if (instance == null) {
11         instance = new GlobalConfig();
12       }
13     }
14     public static GlobalConfig getInstance() {
15       if (instance == null) {
16         syncInit();
17       }
18       return instance;
19     }
20     public Vector getProperties() {
21       return properties;
22     }
23   }
技术分享

  这种处理方式虽然引入了同步代码,但是因为这段同步代码只会在最开始的时候执行一次或多次,所以对整个系统的性能不会有影响。

2.单例对象的属性更新

2.1问题引入:

当一个线程更新单例对象的属性时,如果有另一个线程正在读取,这样就会造成属性值的不一致问题

2.2问题解决:

参照读者/写者的处理方式,设置一个读计数器,每次读取配置信息前,将计数器加1,读完后将计数器减1.只有在读计数器为0时,才能更新数据,同时要阻塞所有读属性的调用。

public class GlobalConfig {
 2     private static GlobalConfig instance = null;
 3     private Vector properties = null;
 4     private GlobalConfig() {
 5       //Load configuration information from DB or file
 6       //Set values for properties
 7     }
 8     private static synchronized void syncInit() {
 9       if (instance = null) {
10         instance = new GlobalConfig();
11       }
12     }
13     public static GlobalConfig getInstance() {
14       if (instance = null) {
15         syncInit();
16       }
17       return instance;
18     }
19     public Vector getProperties() {
20       return properties;
21     }
22     public void updateProperties() {
23       //Load updated configuration information by new a GlobalConfig object
24       GlobalConfig shadow = new GlobalConfig();
25       properties = shadow.getProperties();
26     }
27   }
技术分享






参考资料:

1.

Java单例模式深入详解

http://www.cnblogs.com/hxsyl/archive/2013/03/19/2969489.html

2.

单例模式多线程问题:

http://zhidao.baidu.com/question/2116683855745036107.html


设计模式——单例模式(Java)——考虑多线程环境下的线程安全问题

标签:

原文地址:http://blog.csdn.net/ly969434341/article/details/51366693

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!