您的位置:首页 > 其它

设计模式之单例模式

2017-01-09 18:32 211 查看

1.单例模式

即保证整个系统只有一个实例对象

1.1使用场景可有:

1).数据缓存对象

2).工具方法

1.2实现方式:

通过对构造函数私有化类实现对象单例

2.单例的代码实现

2.1实现方式一

(懒汉式)

Singleton
public class Singleton {

private static Singleton _instance = null;

private Singleton(){
System.out.println("初始化");
}

public static Singleton getInstance(){
if(_instance == null){
_instance = new Singleton();
}
return _instance;
}

public static void doSomething(){
System.out.println("做点东西吧!");
}
}
Client

public class Client{
public static void main(){
Singleton singleton = Singleton.getInstance();
singleton.doSomething();
System.out.println(singleton);
singleton = Singleton.getInstance();
System.out.println(singleton);
}
}
上面这种方式存在问题,当有多线程时,会导致实例被创建多次。于是我们引入同步锁:

2.2同步锁优化

Singleton
public class Singleton{
private static Singleton _instance = null;

private Singleton(){}

public static Singleton getInstance(){
synchronized(Singleton.class){
if(_instance == null){
_instance = new Singleton();
}
return _instance;
}
}
public static void doSomething(){
System.out.println("做点东西吧");
}
}
Client:
public class Client{
public static void main(String[] args){
for(int i = 0;i < 10;i++){
Thread t = new Thread(new Runable(){
public void run(){
Singleton singleton = Singleton.getInstnace();
System.out.println(singleton);
}
});
t.start();
}
}
}


如上,加入同步关键字后会引发效率问题,我们可以加入双检锁,缩小锁的范围

2.3使用双检锁

Singleton
public class Singleton {

private static Singleton _instance = null;

private Singleton() {
}

/**
* new Singleton() 这句话其实是包含三个逻辑 1.给Singleton实例创建空间 2.初始化Singleton的构造器
* 3.把Singleton这个实例的引用赋值给_instance (_instance就不为null了)
* 由于jvm运行期的优化,第二部和第三步的顺序是不能保证的 这样就会导致出现两种情况1,2,3或1,3,2
*/
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null) {
_instance = new Singleton();
}
}
}
return _instance;
}

public static void doSomething() {
System.out.println("做点东西吧");
}
}


Client




public class Client{
public static void main(String[] args){
for(int i = 0;i < 10;i++){
Thread t = new Thread(new Runnable(){
public void run(){
Singleton singleton = Singleton.getInstance();
System.out.println(singleton);
}
});
t.start();
}
}
}
如上这种实现方式中 new  Singleton()包含三个逻辑:
1.给Singleton实例创建空间
2.初始化Singleton的构造器
3.把singleton这个实例的引用赋值给_instance (_instance就不为null了)

假如第一个线程调用获取实例的方法时,执行到new Singleton();这句话,只执行了1,3两个步骤,
这个时候_instance已经不为null了,但是构造器没有初始化完成,然后第二个线程进来,由于此时
_instance已经不为null了,所以在判读非空的时候就直接返回了,这时如果线程2使用这个构造器没
有初始化完成的singleton对象的话,就会报错!

解决方案有:
1.jdk1.5及1.5以后版本可以在变量中声明volatile关键字,让线程强制读取主内容中的变量,而不去读取变量副本。
2.通过饿汉式的单例模式来解决
3.使用静态类来保存instance

2.4使用volatile关键字

Singleton
public class Singleton {

private static volatile Singleton _instance = null;

private Singleton(){}

public static Singleton getInstance(){
if(_instance == null){
synchronized(Singleton.class){
if(_instance == null){
_instance = new Singleton();
}
}
}
return _instance;
}

public static void doSomething(){
System.out.println("做点东西吧!");
}
}

2.5饿汉式

public class Singleton{

private final static Singleton _instance = new Singleton();

private Singleton(){
System.out.println("初始化!");
}

public static Singleton getInstance(){
return _instance;
}

public static void doSomething(){
System.out.println("做点东西吧!");
}
}


Client

public class Client {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("singleton.Singleton");
Singleton.getInstance().doSomething();
}
}

2.6静态类保存instance的方式

Singleton
public class Singleton{

private static class SingletonHolder{
static Singleton _instance = new Singleton();
}

private Singleton(){
System.out.println("初始化!");
}

public static Singleton getInstance(){
return SingletonHolder._instance;
}

public static void doSomething(){
System.out.println("做点什么吧!");
}

}


Client
public class Client {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("singleton.Singleton");
Singleton.getInstance().doSomething();
}
}


小结:在软件设计当中,我们应该遵循一个法则,简单,正确。不为了炫耀技术来实现需求,只有简单,正确的实现方式,它生命周期才是最长,因它可维护性高。所以选择懒汉还是饥汉的方式是根据具体的场景定的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息