挑战常规--这样写单例是错的!

说到单例,网上教程和不少人信手拈来:java

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;
	}
}

 

下面驳斥所谓的省内存。spa

public class SingleTest
{
 
	public static void main(String[] args) throws  Exception
	{ 
		System.out.println("启动线程");
		System.in.read();
	}

}

 首先,不用单例时,难作别的写法就会加载单例?没有引用使用单例类时,固然都不会加载单例。线程

看图,并不会加载建立单例,控制台也不会输出建立单例。3d

其次,既然预约要使用单例,那么都会加载建立一次。code

public class SingleTest
{
 
	public static void main(String[] args) throws  Exception
	{ 
		System.out.println("启动线程");
		Single.getInstance();
		System.in.read();
	}

}

 看图,不管哪一种模式单例都会被引用加载对象

 

是否是用synchronized建立单例就没有用处了呢?blog

并非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);
    }
    
}
相关文章
相关标签/搜索