废话不多说 直接上代码
- 饿汉式
public class MyApplication extends Application {
private MyApplication() {
}
private static MyApplication app = new MyApplication();
public static MyApplication getInstance() {
return app;
}
}
类加载就会创建实例,线程安全。因为虚拟机保证了类只会加载一次,在装载类的时候是不会并发的
缺点:无法携带参数 无法实现延迟加载
- 懒汉式
public class MyApplication extends Application {
private MyApplication() {
}
private static MyApplication app;
public static MyApplication getInstance() {
if (app == null) {
app = new MyApplication();
return app;
}
return app;
}
}
适合单线程模式 延迟加载
缺点:多线程调用情况下,会出现多个实例。例如:当两个线程同时运行到判断app是否为空的if语句,并且app确实没有创建完毕,那么两个线程都会创建一个实例
优点:可携带参数 延迟加载
- 双重锁版本(推荐)
public class MyApplication extends Application {
private MyApplication() {
}
private volatile static MyApplication app;
public static MyApplication getInstance() {
if (app == null) {
synchronized (MyApplication.class) {
if (app == null) {
app = new MyApplication();
return app;
}
}
}
return app;
}
}
注意:
- volatile修饰意思是怕出现多CPU处理出现并发问题 ,可能引发错乱等多个实例的问题 建议查下volatile关键字。
- synchronized修饰意思是必须线程是排队一个一个进去的,处理了多线程的问题,同时加锁会很耗时的操作,但是不得不为之
- 第一个IF是判断需不需要 进入加锁判断 如果有实例直接返回实例,第二个IF是来判断是否为null(因为用了synchronized,不会出现多线程的情况,所以保证实例唯一)
- 内部静态方法类
public class MyApplication extends Application {
private MyApplication() {
}
private static class ChildApp {
private final static MyApplication app = new MyApplication();
}
public static MyApplication getInstance() {
return ChildApp.app;
}
}
注意:
由于内部类不会在加载外部类的时候进行加载,那么这个也属于懒加载。但是这种延迟加载的加载也是class的加载,jvm保证只有一次所以同样线程安全
优点:效率比双重锁略高
缺点:无法携带参数
- 枚举(不推荐)
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
枚举不适用于android,谷歌说的。
总结:根据具体需求使用具体单例,比如涉及多线程操作,并且无需携带参数就用内部静态类,如果是带参数那就双重锁等。