0
点赞
收藏
分享

微信扫一扫

单例模式(含线程锁关键字)


单例就是只有一个例子,只有一个对象,不允许别人再创建对象。


饿汉式(初始化即创建对象)

class Single{

private static Single s = new Single();

private Single(){}

public static Single getInstance(){

return s;

}

}



懒汉式(方法被调用时,才创建对象,也叫做对象的延时加载)

class Single{

  private static Single s = null;

  private Single(){}

  public static Single getInstance(){//当多人同时调用此方法时有可能出状况

    if(s == null)   //语句①

      s = new Single();//语句②

    return s;

  }

}



懒汉式看似省空间,却有可能在多线程时出问题。

举个只有两个线程的例子:线程A被单核CPU执行到①,单核CPU切入线程B去执行①,仍然会通过判断,此时A,B都会执行语句②。


改进后的安全懒汉式(低效,在方法上增加了线程锁):

class Single{

private static Single s = null;

private Single(){}

public synchronized static Single getInstance(){

if(s == null) //语句①

s = new Single();//语句②

return s;

}

}


tips:

线程锁就是synchronized后边的参数,汉语版的API中作者称之为对象监视器。线程锁有两个状态,一个锁住一个打开,打开的时候线程就能进去,关闭的时候,线程就会在门前等待,直到锁打开才会进去。 

synchronized相当于一个标示符表示它所跟随的大括号内的内容是同步代码块,执行这部分代码块就要判断线程锁的状态。


再次改进后最终的懒汉式(在方法内部增加线程锁)

class Single{

private static Single s = null;

private Single(){}

public static Single getInstance(){

if(s == null){ //语句①

synchronized (Single.class){ //语句② 这样就会最多判断两次线程锁

if(s == null) //语句③

s = new Single();//语句④

}

}

return s;

}

}




解析一下:线程A执行语句①通过,执行语句②通过,此时CPU切入线程B执行到语句①通过,执行到语句②未通过,

然后CPU切入线程A继续执行,通过语句③和④并解除线程锁,CPU再次切入线程B,此时会通过语句②,执行语句③,

如果没有语句③又悲剧了。。。


总结,既然有这么一个单例类,肯定你是要用它的,你要用它一定会开辟内存存放它的对象,

懒汉实在是浪费时间又没什么实际意义,所以建议选择饿汉式的单例模式。




举报

相关推荐

0 条评论