单例设计模式
1.饿汉式(静态常量)(可用)
- 构造器私有化
- 类的内部创建对象
- 向外暴露一个静态的公共方法
class Singleton{
//使用private防止new
private Singleton(){
}
//类的内部创建对象
private final static Singleton instance = new Singleton();
//向外暴露一个静态的公共方法
public static Singleton getInstance(){
return instance;
}
}
优缺点:
优点 | 写法简单,在类装载的时候完成实例化,避免了线程同步问题 |
---|---|
缺点 | 在类装载的时候就完成实例化,没有达到lazy Loading的效果,如果一直没有用到,会造成内存的浪费 |
无法保证是自己触发的静态的方法
2.饿汉式(静态代码块)(可用)
class Singleton{
//使用private防止new
private Singleton(){
}
//类的内部创建对象
private static Singleton instance;
static{ //在静态代码块里创建
instance = new Singleton();
}
//向外暴露一个静态的公共方法
public static Singleton getInstance(){
return instance;
}
}
优缺点和静态常量一样
3.懒汉式(线程不安全)
class Singleton{
//类的内部创建对象
private static Singleton instance;
//使用private防止new
private Singleton(){
}
//使用的時候才创建出来 懒汉式
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
优点 | 起到了lazy Loading的效果 |
---|---|
缺点 | 只能在单线程下使用,在多线程下,一个线程进入了if语句中,没来得及执行完,另一个线程也通过了这个判断语句,这时候就会产生多个实例,所以在多线程下不可以使用和这个方式 |
4.懒汉式(线程安全,同步方法)
class Singleton{
//类的内部创建对象
private static Singleton instance;
//使用private防止new
private Singleton(){ }
//加入了同步代码,解决线程不安全问题
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
优点 | 解决了线程不安全的问题 |
---|---|
缺点 | 效率很低,方法只需要执行一次就可以了,但是使用这个方法需要执行很多次,都要进行同步 |
5.懒汉式(线程安全,同步代码块)
class Singleton{
//类的内部创建对象
private static Singleton instance;
//使用private防止new
private Singleton(){ }
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
线程不安全(有人写)不可以启到线程同步的作用(==错误==)
6.双重检查(推荐使用)
class Singleton{
//volatile防止指令重排
private static volatile Singleton instance;
//使用private防止new
private Singleton(){ }
//双重检查,解决线程安全问题,实现了懒加载的方式
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
优点 | Double-Check多线程中经常使用,保证了线程的安全,避免重复的方法同步,延迟加载,效率较高 |
---|---|
结论 | 推荐使用 |
7.静态内部类(推荐使用)
class Singleton{
//使用private防止new
private Singleton(){ }
//双重检查,解决线程安全问题,实现了懒加载的方式
public static SingletonInstance{
private static final Stingleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
实现了线程安全,使用延迟加载(很好的一种模式),效率高
静态内部类装载的时候是安全的
8.枚举(推荐使用)
enum Singleton{
INSTANCE;
public void say(){
System.out.println("ok");
}
}
借助JDK1.5的枚举来实现,避免多线程同步问题,还能防止反序列化重新创建新的对象
是Josh Bloch提倡的方式
9.单例模式在Runtime使用
?Runtime:
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
10.单例模式注意事项
- 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
- 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是用new
- 单例模式使用的场景:
- 需要频繁的进行创建和销毁的对象
- 创建对象时耗时过多或耗费资源过多(重量级对象)但又经常使用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂)