课前准备:static
static 可以用来修饰:成员变量、成员方法、代码块享。
-
static 变量: 在内存中只有一个拷贝,JVM在加载类的过程中完成静态变量的内存分配且只分配一次内存,区别于实例变量(每次创建实例,都会分配一次内存)
-
static方法: 可以直接通过类名调用,static 方法中不能访问非静态成员方法和非静态成员变量。
-
static代码块:JVM加载类时会执行这些静态代码块,按照出现的先后顺序依次执行一次。
-
1.饿汉模式
public class A {
private static A instance = new A();
private A (){
}
public static A getInstance() {
return instance;
}
}
这种方式利用了上面描述的static 变量加载时机,在类加载时候就完成了初始化,但getInstance()这个方法显然没有懒加载效果(用到的时候在初始化)。
- 2.懒汉模式(线程不安全)
public class A {
private static A instance;
private A (){
}
public static A getInstance() {
if (instance == null) {
instance = new A();
}
return instance;
}
}
这种设计模式满足了懒加载,且在整个内存中也只有一份变量,但是在多线程情况下有问题。
- 3.懒汉模式(线程安全)
public class A {
private static A instance;
private A (){
}
public static synchronized A getInstance() {
if (instance == null) {
instance = new A();
}
return instance;
}
}
通过加锁的方式保证了线程的安全性,但是每次调用getInstance方法都进行同步,开销较大。
- 4.双重检查
public class A {
private volatile static A instance;
private A (){
}
public static A getInstance() {
if (instance== null) {
synchronized (A.class) {
if (instance== null) {
instance= new A();
}
}
}
return singleton;
}
}
但是由于JVM加载的乱序执行功能,所以也可能存在线程不安全的情况。
- 5.静态内部类 blog.csdn.net/mnb65482/ar… 原理分析 既实现了懒加载又保证了线程安全
public class Singleton {
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
-
6.枚举类
-
7.使用容器实现
public class A {
private static Map<String, Object> objMap = new HashMap<String,Object>();
public static void registerService(String key, Object instance) {
if (!objMap.containsKey(key) ) {
objMap.put(key, instance) ;
}
}
public static ObjectgetService(String key) {
return objMap.get(key) ;
}
}
通过key、value 的形式保存、获取唯一的实例。