作者 :我想嘿嘿
来源:https://www.cnblogs.com/loveheihei
说到单例,网上教程和很多人信手拈来:
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;
}
}
是不是用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;
}
}
推荐阅读
技术之路从来没那么简单。一个人可以跑得更快,但一个人可以跑得更远。扫描下方二维码添加小助手微信,回复「入群」与两千小伙伴一起共同前行。
公众号@Java技术精选,关注 Java 程序员的个人成长,分享最新技术资讯与技术干货。与你成长有关的,我们这里都有。
↑↑创作不易,如果喜欢请转发↑↑