单例模式就是保证一个类只能有一个对象,并提供一个访问该实例的全局的访问点。
单例模式在一些只需要有一个实例的场景下比如windows的任务管理器,保证只创建一个对象避免不必要的系统资源消耗。
单例模式按照创建实例的时间不同分为类一加载就创建对象的饿汉式和延时创建对象的懒汉式。
饿汉式的是类一加载就创建对象,天然线程安全;方法没有同步,调用效率高;但是没有延时加载更节省系统资源的优势。
代码如下:
class SingletonDemo{
private SingletonDemo(){
}
private static SingletonDemo instance=new SingletonDemo();
public static SingletonDemo getInstance(){
return instance;
}
}
懒汉式是当需要对象时才创建对象,线程安全,方法要同步调用效率低。但是比饿汉式更节省资源。
代码如下:
class SingletonDemo2{
private SingletonDemo2(){
}
private static SingletonDemo2 instance2;
public static synchronized SingletonDemo2 getInstance2(){
if (instance2==null)
{
instance2=new SingletonDemo2();
}
return instance2;
}
}
为了解决饿汉式和懒汉式的缺点:
我们还有其他的优化。
1.双重检查锁式,
在懒汉式中我们是每次调用方法就要同步,现在我们把,同步代码块移动至if==null上,当不为空
时才用sybchronized关键字。
2.静态内部类实现方式(兼顾线程安全、懒加载和高调用效率优点)
代码如下
class SingletonDemo3{
private SingletonDemo3(){
}
private static class SingletonClassInstance{
private static final SingletonDemo3 Instance6=new SingletonDemo3();
}
public static SingletonDemo3 getInstance(){
return SingletonClassInstance.Instance6;
}
}
3.枚举方式:
代码如下:
/**
* 枚举类天然就是单例的,可以避免其他方式的反射和反序列化的漏洞;
* 效率也挺高的
* 缺点就是没有懒加载
*/
public enum SingletonDemo5 {
INSTANCE5;
//也可以在这里定义一些其他方法
public void getInstance(){
}
}
单例模式的应用场景:
1.项目中读取配置文件的类,一般只有一个对象,没有必要每次读取配置文件都new一个对象。
2.网站的计数器一般都采用单例模式实现,否则难以同步。
3.应用程序的日志应用,一般都采用单例模式。因为一般共享的日志文件一直处于打开状态,
只有一个实例的情况下内容才好追加。
4.数据库连接池都是单例模式,因为数据库连接是一种数据库资源,每个实例都消耗大量资源。
5.操作系统的文件系统也是单例模式,一个操作系统只能有一个文件系统。
6.Application也是单例的典型应用(servelet编程会涉及到)
7.在spring中每个Bean默认就是单例的,这样spring容器就可以管理。
8.在spring MVC框架\struts1框架中,每一个控制器都是单例。
9.在servelet编程中,每一个 servelet也是单例。
单例的需用;
1.单例对象消耗的资源少,不需要延时加载
枚举类好于饿汉式
2.单例独享消耗的资源多,需要延时加载
静态内部类式好于懒汉式