挑战常规--这样写单例是错的!
程序员文章站
2022-07-02 14:11:47
说到单例,网上教程和很多人信手拈来: 自信满满,称之为懒汉加载模式,言之节省内存,用时才会自动创建。在我看来,这种写法完全是错误的,愚蠢至极,这不是脱裤子放屁,这是脱完裤子再提取裤子再放屁。 正确写法就是最简单的: 下面驳斥所谓的省内存。 首先,不用单例时,难道别的写法就会加载单例?没有引用使用单例 ......
说到单例,网上教程和很多人信手拈来:
public class single
{
private volatile static single instance;
private single()
{
system.out.println("创建单例");
}
public static single getinstance()
{
if (instance == null)
{
synchronized (single.class)
{
if (instance == null)
{
instance = new single();
}
}
}
return instance;
}
}
自信满满,称之为懒汉加载模式,言之节省内存,用时才会自动创建。在我看来,这种写法完全是错误的,愚蠢至极,这不是脱裤子放屁,这是脱完裤子再提取裤子再放屁。
正确写法就是最简单的:
public class single
{
private static single instance=new single();
private single()
{
system.out.println("创建单例");
}
public static single getinstance()
{
return instance;
}
}
下面驳斥所谓的省内存。
public class singletest
{
public static void main(string[] args) throws exception
{
system.out.println("启动线程");
system.in.read();
}
}
首先,不用单例时,难道别的写法就会加载单例?没有引用使用单例类时,当然都不会加载单例。
看图,并不会加载创建单例,控制台也不会输出创建单例。
其次,既然预定要使用单例,那么都会加载创建一次。
public class singletest
{
public static void main(string[] args) throws exception
{
system.out.println("启动线程");
single.getinstance();
system.in.read();
}
}
看图,无论哪种模式单例都会被引用加载
是不是用synchronized创建单例就没有用处了呢?
并不是,synchronized是用于解决多线程访问问题。带参数的单例创建才应该使用懒汉模式
因为并不能预期,什么时候参数被传入。简单模式下并不清楚传入什么参数,或参数对象未初始化。
public class single
{
private volatile static single instance ;
public single(context context)
{
system.out.println("创建单例");
}
public static single getinstance(context context)
{
if (instance == null)
{
synchronized (single.class)
{
if (instance == null)
{
instance = new single(context);
}
}
}
return instance;
}
}
为什么说这个是为了解决多线程访问呢,先看如果不加锁会发生什么
public class single { private static single instance ; public single(context context) { system.out.println("创建单例"); } public static single getinstance(context context) { if (instance == null) { instance = new single(context); } return instance; } }
public class singletest
{
public static void main(string[] args) throws exception
{
executorservice pool = executors.newcachedthreadpool();
arraylist<callable<void>> runners=new arraylist<>();
for(int i=0;i<10;i++)
{
runners.add(()->{
single.getinstance(new context());
return null;
});
}
system.out.println("启动线程");
pool.invokeall(runners);
pool.shutdown();
system.in.read();
}
}
不加锁情况,结果看图
加锁情况,结果看图
总结,无参构造单例无需复杂的加入synchronized,而未确定的传参单例需要加synchronized保证多线程访问安全。
思考,如果传入的参数确定,怎么写才最优呢?下面类似写法是否合理:
public class single
{
private static single instance =new single(context.instance);
public single(context context )
{
system.out.println("创建单例");
}
public static single getinstance( )
{
return instance;
}
}
@weblistener public class myservletcontextlistener implements servletcontextlistener { public void contextdestroyed(servletcontextevent sce) { } public void contextinitialized(servletcontextevent sce) { single.getinstance(sce); } }
上一篇: Web自动化
下一篇: jQuery自适应-3D旋转轮播图