论坛首页 Java企业应用论坛

非线程同步机制下线程安全的单例模式——最优的单例模式

浏览 15271 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-05-18   最后修改:2011-05-18
nianien 写道

zhang34082 写道
第三种与第一种 是一样的机制,都是通过静态块来初始化的"



怎么能是一样的呢?
都说了实例化的时间不一样
第一种,只要你第一次引用了类,都会触发单例对象的实例化
而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的


类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。
public static void main(String[] args) {
       
        SingleTon  instance = SingleTon .getInstance();// 在这个地方设断点
    }
可以通过这个在测试。是否是延迟加载的
0 请登录后投票
   发表时间:2011-05-18  
zhang34082 写道
littcai 写道
第一种是延迟加载的,优

不是延迟加载的,都是类加载的时候 初始化实例变量的,没区别


在类加载的时候,静态变量与静态块 从上而下逐个执行的。
0 请登录后投票
   发表时间:2011-05-18  
zhang34082 写道
nianien 写道

zhang34082 写道
第三种与第一种 是一样的机制,都是通过静态块来初始化的"



怎么能是一样的呢?
都说了实例化的时间不一样
第一种,只要你第一次引用了类,都会触发单例对象的实例化
而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的


类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。
public static void main(String[] args) {
       
        SingleTon  instance = SingleTon .getInstance();// 在这个地方设断点
    }
可以通过这个在测试。是否是延迟加载的

public class SingleTon {

private SingleTon(){}

public static SingleTon getInstance() {
return SingleTonHolder.instance;
}

static class SingleTonHolder{
private static SingleTon instance=new SingleTon();
}
}
你敢实际测试一下么?
你不调用,它会实例化?



0 请登录后投票
   发表时间:2011-05-18   最后修改:2011-05-18
nianien 写道
zhang34082 写道
nianien 写道

zhang34082 写道
第三种与第一种 是一样的机制,都是通过静态块来初始化的"



怎么能是一样的呢?
都说了实例化的时间不一样
第一种,只要你第一次引用了类,都会触发单例对象的实例化
而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的


类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。
public static void main(String[] args) {
       
        SingleTon  instance = SingleTon .getInstance();// 在这个地方设断点
    }
可以通过这个在测试。是否是延迟加载的

public class SingleTon {

private SingleTon(){}

public static SingleTon getInstance() {
return SingleTonHolder.instance;
}

static class SingleTonHolder{
private static SingleTon instance=new SingleTon();
}
}
你敢实际测试一下么?
你不调用,它会实例化?

多的俺不说了,如果你觉得他是延迟加载的,你提供测试方法出来,或者说下静态类、嵌套类中静态实例在类加载的时候是怎么加载的
0 请登录后投票
   发表时间:2011-05-18   最后修改:2011-05-18
nianien 写道
个人认为下面是Java实现的最优的单例模式
这种实现方法采用内部静态类,
只在第一次调用getInstance方法的时候才实例化单例对象
如果不调用,就不会进行单例对象的实例化,
因此,既实现了延迟实例化,又不需要线程同步
引用

public class SingleTon {

private SingleTon(){}

public static SingleTon getInstance() {
return SingleTonHolder.instance;
}

private static class SingleTonHolder{
private static SingleTon instance=new SingleTon();
}
}



下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化
引用

public class SingleTon {

private SingleTon(){}
         private static SingleTon s=new SingleTon();

public static SingleTon getInstance() {
return s;
}

}



这种单例模式,和上面的实现差不多,虽然能够延迟单例对象的实例化,但是都是在同一时间范围内完成的
引用

public class SingleTon {

private SingleTon(){}
private static SingleTon s;

static {
s=new SingleTon();
}

public static SingleTon getInstance() {
return s;
}
}


下面这种就是


还有两种解决方案,不在本帖讨论范围之内
1.采用synchronized的关键字同步getInstance方法
2.采用synchronized的关键字同步代码段,双重是否为空的判断


下面是测试结果,以证明本人想法的正确性:
public class SingleTon {
    static {
            System.out.println("悲催了,被加载了!");
    }
    private SingleTon() {
        System.out.println("悲催了,被实例化了!");
    }

    public static SingleTon getInstance() {
        return SingleTonHolder.instance;
    }

     public static void otherMethod() {
         System.out.println("悲催了,调用其他方法了!");
    }
    private static class SingleTonHolder {
        private static SingleTon instance = new SingleTon();
    }

 }


public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        Class.forName("com.lining.SingleTon");
        SingleTon.otherMethod();
        SingleTon.getInstance();     
    }
}


output:
悲催了,被加载了!
悲催了,调用其他方法了!
悲催了,被实例化了!
0 请登录后投票
   发表时间:2011-05-18  
zhang34082 写道
nianien 写道
zhang34082 写道
nianien 写道

zhang34082 写道
第三种与第一种 是一样的机制,都是通过静态块来初始化的"



怎么能是一样的呢?
都说了实例化的时间不一样
第一种,只要你第一次引用了类,都会触发单例对象的实例化
而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的


类加载的时候,对于静态变量与块,从上而下逐个执行。延迟加载是用的时候才实例化。
public static void main(String[] args) {
       
        SingleTon  instance = SingleTon .getInstance();// 在这个地方设断点
    }
可以通过这个在测试。是否是延迟加载的

public class SingleTon {

private SingleTon(){}

public static SingleTon getInstance() {
return SingleTonHolder.instance;
}

static class SingleTonHolder{
private static SingleTon instance=new SingleTon();
}
}
你敢实际测试一下么?
你不调用,它会实例化?

多的俺不说了,如果你觉得他是延迟加载的,你提供测试方法出来,或者说下静态类、嵌套类中静态实例在类加载的时候是怎么加载的

测试结果出来了,你还有什么话说?
唉,眼高手低的人~~~~~~
0 请登录后投票
   发表时间:2011-05-18   最后修改:2011-05-18
nianien 写道
下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化
引用

public class SingleTon {
private SingleTon(){}
         private static SingleTon s=new SingleTon();
public static SingleTon getInstance() {
return s;
}
}



这种单例模式,和上面的实现差不多,虽然能够延迟单例对象的实例化,但是都是在同一时间范围内完成的
引用

public class SingleTon {
private SingleTon(){}
private static SingleTon s;
static {
s=new SingleTon();
}
public static SingleTon getInstance() {
return s;
}
}


上下两份代码编译后的字节码一模一样

何来上面一种“但是,不能实现延迟实例化
而下面一种“虽然能够延迟单例对象的实例化

也就是说:
         private static SingleTon s=new SingleTon();


完全等价于:
	private static SingleTon s;
	static {
		s=new SingleTon();
	}


静态变量的初始化发生在  类被加载的时候(缺省情况下,被加载的类会在加载时被初始化,除非明确指定延迟初始化),
    public static Class<?> forName(String name, boolean initialize, ClassLoader loader)


0 请登录后投票
   发表时间:2011-05-18  
nianien 写道
zhang34082 写道
第三种与第一种 是一样的机制,都是通过静态块来初始化的

怎么能是一样的呢?
都说了实例化的时间不一样
第一种,只要你第一次引用了类,都会触发单例对象的实例化
而第三种,只要你不去调用getInsance方法,是不永远不会实例化单例对象的

static是什么?哪来的延迟。
0 请登录后投票
   发表时间:2011-05-18   最后修改:2011-05-18
nianien 写道

引用

public class SingleTon {

private SingleTon(){}

public static SingleTon getInstance() {
return SingleTonHolder.instance;
}

private static class SingleTonHolder{
private static SingleTon instance=new SingleTon();
}
}



这种方式下的确 是延迟到getInstance()方法被调用的时候才实例化new SingleTon();


nianien 写道
下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化
引用

public class SingleTon {

private SingleTon(){}
         private static SingleTon s=new SingleTon();

public static SingleTon getInstance() {
return s;
}

}



这种方式下new SingleTon();是在SingleTon类被加载的时候才初始化的,SingleTon类被加载的时机是
该类第一次被引用的时候。所以,什么时候加载不确定。
但一般引用SingleTon类的代码被执行的时候,也就是需要使用的时候了,所以实质上也有延迟的效果。

比如下面的代码:
public class SingleTon {
	private static SingleTon s = new SingleTon();

	public static SingleTon getInstance() {
		return s;
	}

	static {
		System.out.println("悲催了,被加载了!");
	}

	private SingleTon() {
		System.out.println("悲催了,被实例化了!");
	}
}

public class Test {

	public static void main(String[] args) throws ClassNotFoundException {
		Class.forName("my.SingleTon", false, Test.class.getClassLoader());
		System.out.println("做点其他事情...");
		SingleTon.getInstance();
	}
}


Test类main方法的第一行加载SingleTon类,但不会初始化SingleTon。
SingleTon类被初始化是 直到调用SingleTon.getInstance();方法的时候。
所以,这种方法也是具有延迟加载效果的。
0 请登录后投票
   发表时间:2011-05-18  
sswh 写道
nianien 写道
下面这种单例模式是应用最多的,同样不存在线程同步的问题
但是,不能实现延迟实例化
引用

public class SingleTon {
private SingleTon(){}
         private static SingleTon s=new SingleTon();
public static SingleTon getInstance() {
return s;
}
}



这种单例模式,和上面的实现差不多,虽然能够延迟单例对象的实例化,但是都是在同一时间范围内完成的
引用

public class SingleTon {
private SingleTon(){}
private static SingleTon s;
static {
s=new SingleTon();
}
public static SingleTon getInstance() {
return s;
}
}


上下两份代码编译后的字节码一模一样

何来上面一种“但是,不能实现延迟实例化
而下面一种“虽然能够延迟单例对象的实例化

也就是说:
         private static SingleTon s=new SingleTon();


完全等价于:
	private static SingleTon s;
	static {
		s=new SingleTon();
	}


静态变量的初始化发生在  类被加载的时候(缺省情况下,被加载的类会在加载时被初始化,除非明确指定延迟初始化),
    public static Class<?> forName(String name, boolean initialize, ClassLoader loader)



静态代码块和静态成员变量加载是有先后顺序的好不好?
public class InitDemo {
    private static Demo d1 = new Demo(1);
    private static Demo d2 = new Demo(2);
    private static Demo d3 = new Demo(3);

    static {
        d1 = new Demo(0);
        d1 = new Demo(0);
        d1 = new Demo(0);
    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println();
    }

}

class Demo {
    public Demo(int count) {
        System.out.println(count);
    }
}
从测试结果你可以看到,静态代码块执行顺序要晚于静态字段,因此,我们常用静态代码块改写初始值,字段默认初始值为null,执行静态代码块就是改写null值,它并不是最初的赋值
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics