扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
1.首先 所有的类都是第一次被引用时才会加载到JVM中。也就是说全都是延迟加载,而不是预先加载。
成都创新互联公司专业为企业提供武安网站建设、武安做网站、武安网站设计、武安网站制作等企业网站建设、网页设计与制作、武安企业网站模板建站服务,十载武安做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
2.“静态类将只会随JVM装载一次,所以只会创建一个Foo对象”,这句话的意思是说,随着类LazyFoo被第一次引用,JVM会载入类LazyFoo,同时执行类的静态初始化。
什么是类的静态初始化?
类被载入JVM之后,各个语句之间的执行顺序是如何的呢?
#当第一次引用类之后#
1.类的静态初始化(包括类的静态块)
#当创建类的对象后#
2.类的非静态初始化(同样包括类的非静态块)
3.类的构造函数
public static Foo foo = new Foo();
这一句就是类的静态初始化,他仅会在类被载入时执行一次。
实际上你的这个单例模式的代码还是有些问题的。似乎不能达成单例效果,除非添加一个private Foo()构造函数。
我写一个单例模式给你看看吧。
public class Foo {
private static Foo sc;
private Foo() {
}
public static Foo getSC() {
if (sc == null) {
sc = new Foo();
}
return sc;
}
}
这个可能是驱动问题,建议用第三方驱动,如果不是驱动问题建议考虑下是不是代码或配置有什么问题。
看你这个错误的字面意思好像是对同一个字段在结果集里面不能取两次以上。所以我怀疑你这段不是hibernate做的,再有要不就是你的映射是不是有问题。仔细再找找看。
延迟加载的核心思想是动态代理模式。首先并不加载数据,而是创建一个代理对象,需要数据的时候由代理对象去加载所需数据。你前两次都可以登录,说明根本不是延迟加载的原因。
你可以debug,看在哪一功能就卡住了,是全表扫描了还是代码哪里不严谨了。
首先:SCRIPT language=JavaScript src="js/photo.js" /SCRIPT
这不是java,这是JavaScript,简称js。
你要的功能:
SCRIPT language=JavaScript src="" id="aaa" /SCRIPT
script
function oOpen(){
document.getElementById("aaa").src="js/photo.js";
}
var oTime = window.setTimeout("oOpen()",5000);
/script
5000表示5秒后,你也可以自己设置时间。
我从我的博客里把我的文章粘贴过来吧,对于单例模式模式应该有比较清楚的解释:
单例模式在我们日常的项目中十分常见,当我们在项目中需要一个这样的一个对象,这个对象在内存中只能有一个实例,这时我们就需要用到单例。
一般说来,单例模式通常有以下几种:
1.饥汉式单例
public class Singleton {
private Singleton(){};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
这是最简单的单例,这种单例最常见,也很可靠!它有个唯一的缺点就是无法完成延迟加载——即当系统还没有用到此单例时,单例就会被加载到内存中。
在这里我们可以做个这样的测试:
将上述代码修改为:
public class Singleton {
private Singleton(){
System.out.println("createSingleton");
};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
public static void testSingleton(){
System.out.println("CreateString");
}
}
而我们在另外一个测试类中对它进行测试(本例所有测试都通过Junit进行测试)
public class TestSingleton {
@Test
public void test(){
Singleton.testSingleton();
}
}
输出结果:
createSingleton
CreateString
我们可以注意到,在这个单例中,即使我们没有使用单例类,它还是被创建出来了,这当然是我们所不愿意看到的,所以也就有了以下一种单例。
2.懒汉式单例
public class Singleton1 {
private Singleton1(){
System.out.println("createSingleton");
}
private static Singleton1 instance = null;
public static synchronized Singleton1 getInstance(){
return instance==null?new Singleton1():instance;
}
public static void testSingleton(){
System.out.println("CreateString");
}
}
上面的单例获取实例时,是需要加上同步的,如果不加上同步,在多线程的环境中,当线程1完成新建单例操作,而在完成赋值操作之前,线程2就可能判
断instance为空,此时,线程2也将启动新建单例的操作,那么多个就出现了多个实例被新建,也就违反了我们使用单例模式的初衷了。
我们在这里也通过一个测试类,对它进行测试,最后面输出是
CreateString
可以看出,在未使用到单例类时,单例类并不会加载到内存中,只有我们需要使用到他的时候,才会进行实例化。
这种单例解决了单例的延迟加载,但是由于引入了同步的关键字,因此在多线程的环境下,所需的消耗的时间要远远大于第一种单例。我们可以通过一段测试代码来说明这个问题。
public class TestSingleton {
@Test
public void test(){
long beginTime1 = System.currentTimeMillis();
for(int i=0;i100000;i++){
Singleton.getInstance();
}
System.out.println("单例1花费时间:"+(System.currentTimeMillis()-beginTime1));
long beginTime2 = System.currentTimeMillis();
for(int i=0;i100000;i++){
Singleton1.getInstance();
}
System.out.println("单例2花费时间:"+(System.currentTimeMillis()-beginTime2));
}
}
最后输出的是:
单例1花费时间:0
单例2花费时间:10
可以看到,使用第一种单例耗时0ms,第二种单例耗时10ms,性能上存在明显的差异。为了使用延迟加载的功能,而导致单例的性能上存在明显差异,
是不是会得不偿失呢?是否可以找到一种更好的解决的办法呢?既可以解决延迟加载,又不至于性能损耗过多,所以,也就有了第三种单例:
3.内部类托管单例
public class Singleton2 {
private Singleton2(){}
private static class SingletonHolder{
private static Singleton2 instance=new Singleton2();
}
private static Singleton2 getInstance(){
return SingletonHolder.instance;
}
}
在这个单例中,我们通过静态内部类来托管单例,当这个单例被加载时,不会初始化单例类,只有当getInstance方法被调用的时候,才会去加载
SingletonHolder,从而才会去初始化instance。并且,单例的加载是在内部类的加载的时候完成的,所以天生对线程友好,而且也不需要
synchnoized关键字,可以说是兼具了以上的两个优点。
4.总结
一般来说,上述的单例已经基本可以保证在一个系统中只会存在一个实例了,但是,仍然可能会有其他的情况,导致系统生成多个单例,请看以下情况:
public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
通过一段代码来测试:
@Test
public void test() throws Exception{
Singleton3 s1 = null;
Singleton3 s2 = Singleton3.getInstance();
//1.将实例串行话到文件
FileOutputStream fos = new FileOutputStream("singleton.txt");
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
//2.从文件中读取出单例
FileInputStream fis = new FileInputStream("singleton.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (Singleton3) ois.readObject();
if(s1==s2){
System.out.println("同一个实例");
}else{
System.out.println("不是同一个实例");
}
}
输出:
不是同一个实例
可以看到当我们把单例反序列化后,生成了多个不同的单例类,此时,我们必须在原来的代码中加入readResolve()函数,来阻止它生成新的单例
public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
//阻止生成新的实例
public Object readResolve(){
return SingletonHolder.instance;
}
}
再次测试时,就可以发现他们生成的是同一个实例了。
延迟加载和JAVA没关系。 很多地方都用得到。
主要是为了加快某些过程,让用户等待时间稍微短一些。 比如浏览器一般先加载文本,显示出来以后再加载图片。 这样用户不至于等到所有东西都下载完成以后再显示给用户。
在某些领域,比如软件开发来讲,延迟加载使用合理可以避免CPU和内存高峰。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流