当前位置:   article > 正文

1.2懒汉模式及其问题、静态内部类实现单例模式_package singleton;public class lazysingletonprivat

package singleton;public class lazysingletonprivate lazysingleton0system

懒汉模式代码

  1. package Singleton;
  2. public class LazySingleton {
  3. private static LazySingleton lazySingleton=null;
  4. private LazySingleton() {
  5. }
  6. public static LazySingleton getInstance() {
  7. if(lazySingleton==null)
  8. lazySingleton=new LazySingleton();
  9. return lazySingleton;
  10. }
  11. public static void main(String[] args) {
  12. // TODO Auto-generated method stub
  13. }
  14. }

懒汉模式最主要得就是会在多线程中重复创建 对象实例,若线程较多则会导致内存使用过大,甚至导致程序崩溃。测试代码如下

Test代码:

  1. package Singleton;
  2. public class Test {
  3. public static void main(String[] args) {
  4. Thread t1=new Thread(new T(),"Thread_1");
  5. Thread t2=new Thread(new T(),"Thread_2");
  6. t1.start();
  7. t2.start();
  8. // TODO Auto-generated method stub
  9. }
  10. }

实习Runnable接口代码如下

  1. package Singleton;
  2. public class T implements Runnable {
  3. public void run() {
  4. System.out.println(Thread.currentThread().getName()+" "+LazySingleton.getInstance());
  5. }
  6. public static void main(String[] args) {
  7. // TODO Auto-generated method stub
  8. }
  9. }

虽然运行之后,结果输出得 实例 是同一个实例,但是这个结果是不确定得,也有可能会输出多个实例。即便输出同一个对象实例,但是中间会多次创建对象实例,后一个覆盖前一个对象,会造成内存资源的消耗,所以懒汉模式是一种不可取的方式。

解决方法:利用synchronized加到方法上,锁住这个类

  1. package Singleton;
  2. public class LazySingleton {
  3. private static LazySingleton lazySingleton=null;
  4. private LazySingleton() {
  5. }
  6. public synchronized static LazySingleton getInstance() {
  7. if(lazySingleton==null)
  8. lazySingleton=new LazySingleton();
  9. return lazySingleton;
  10. }
  11. //下面这个形式和上面的是一样的,都是将这个类加了锁,同一时间只允许一个线程访问这个类
  12. // public static LazySingleton getInstance() {
  13. // synchronized(LazySingleton.class) {
  14. // if(lazySingleton==null)
  15. // lazySingleton=new LazySingleton();
  16. // }
  17. // return lazySingleton;
  18. // }
  19. public static void main(String[] args) {
  20. // TODO Auto-generated method stub
  21. }
  22. }

注意:多线程debug,要切换断点设置为Thread模式下,不能是All模式下,Thread模式下,每个线程的断点都可以真的起到作用,但是All模式下,只能断到主线程的断点。

直接将synchronized加在方法上,开销较大,因此我们使用DoubleCheck方式,代码如下

  1. package Singleton;
  2. public class LazyDoubleCheckSingleton {
  3. private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
  4. private LazyDoubleCheckSingleton() {
  5. }
  6. public static LazyDoubleCheckSingleton getInstance() {
  7. if(lazyDoubleCheckSingleton==null) {
  8. synchronized (LazyDoubleCheckSingleton.class) {
  9. if(lazyDoubleCheckSingleton==null)
  10. lazyDoubleCheckSingleton=new LazyDoubleCheckSingleton();
  11. }
  12. }
  13. return lazyDoubleCheckSingleton;
  14. }
  15. public static void main(String[] args) {
  16. // TODO Auto-generated method stub
  17. }
  18. }

有了双重检查后,当进入方法,判断lazyDoubleCheckSingleton是否为null,当不为null时,直接返回lazyDoubleCheckSingleton即可,就省去了锁开销。但是仍有隐患,如下图

步骤2 3在单线程中允许重排序,所以出现上图问题。

改进措施(解决重排序):将成员变量lazyDoubleCheckSingleton加上volatile修饰符,使其写操作具有可见性。(volatile的汇编语言多了一些代码,就是在写操作后使这个内存对象的缓存无效,当再需要用时,需要再从系统内存中读到处理器的缓存里,即可见性)

private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;

基于类初始化的延迟加载:静态内部类

原理:外部类加载时,不一定加载内部类,内部类不加载则不会去初始化instance,故而不占用内存,只有当getInstance()方法第一次被调用时,才会去初始化instance,延迟了单例的实例化,也使得线程安全,代码如下

  1. package Singleton;
  2. public class StaticInnerClassSingleton {
  3. private StaticInnerClassSingleton() {
  4. }
  5. private static class InnerClss{
  6. private static StaticInnerClassSingleton scs=new StaticInnerClassSingleton();
  7. }
  8. public StaticInnerClassSingleton getInstance() {
  9. return InnerClss.scs;
  10. }
  11. public static void main(String[] args) {
  12. // TODO Auto-generated method stub
  13. }
  14. }

存在隐患:静态内部类无法传参

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/157675
推荐阅读
相关标签
  

闽ICP备14008679号