文章

单例

单例

Java 单例写法

double-checked locking

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public final class Singleton {
    private Singleton() { }
    private static volatile Singleton INSTANCE = null;
    public static Singleton getInstance() {
        if(INSTANCE == null) { // t2
            // 首次访问会同步,而之后的使用没有 synchronized
            synchronized(Singleton.class) {
                if (INSTANCE == null) { // t1
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}
  • 为何么要两次判断 null
  • volatile 的作用

HashMap 版本(线程不安全)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ContainerSingleton {

    private ContainerSingleton(){

    }
    private static Map<String,Object> singletonMap = new HashMap<String,Object>();

    public static void putInstance(String key,Object instance){
        if(StringUtils.isNotBlank(key) && instance != null){
            if(!singletonMap.containsKey(key)){
                singletonMap.put(key,instance);
            }
        }
    }

    public static Object getInstance(String key){
        return singletonMap.get(key);
    }
}

这种方式实现的单例是线程不安全的。如果需要线程安全的可以使用 HashTable 但是 HashTable 每次存取都会加上同步锁,性能损耗比较严重。或者使用 ConcurrentHashMap。

ThreadLocal 单例 — 单线程单例

这个单例严格意义上讲并不完全算是单例,它只能算在 单个线程 中的单例,也就是在同一个线程中的它是单例的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ThreadLocalInstance {
    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstanceThreadLocal
             = new ThreadLocal<ThreadLocalInstance>(){
        @Override
        protected ThreadLocalInstance initialValue() {
            return new ThreadLocalInstance();
        }
    };
    private ThreadLocalInstance(){

    }
    public static ThreadLocalInstance getInstance(){
        return threadLocalInstanceThreadLocal.get();
    }
}

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SingletonTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        System.out.println("main thread"+ThreadLocalInstance.getInstance());
        System.out.println("main thread"+ThreadLocalInstance.getInstance());
        System.out.println("main thread"+ThreadLocalInstance.getInstance());
        System.out.println("main thread"+ThreadLocalInstance.getInstance());
        System.out.println("main thread"+ThreadLocalInstance.getInstance());
        System.out.println("main thread"+ThreadLocalInstance.getInstance());
        Thread t1 = new Thread(new T());
        Thread t2 = new Thread(new T());
        t1.start();
        t2.start();
        System.out.println("program end");
    }
}
public class T implements Runnable {
    @Override
    public void run() {
        ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
        System.out.println(Thread.currentThread().getName()+"  "+instance);
    }
}

运行结果:

1
2
3
4
5
6
7
8
9
main threadcom.design.pattern.creational.singleton.ThreadLocalInstance@12edcd21
main threadcom.design.pattern.creational.singleton.ThreadLocalInstance@12edcd21
main threadcom.design.pattern.creational.singleton.ThreadLocalInstance@12edcd21
main threadcom.design.pattern.creational.singleton.ThreadLocalInstance@12edcd21
main threadcom.design.pattern.creational.singleton.ThreadLocalInstance@12edcd21
main threadcom.design.pattern.creational.singleton.ThreadLocalInstance@12edcd21
program end
Thread-0  com.design.pattern.creational.singleton.ThreadLocalInstance@3ec28870
Thread-1  com.design.pattern.creational.singleton.ThreadLocalInstance@7a56389b

这个单例之算是个伪单例,只能在一个线程里面实现单例

Android 中的 ThreadLocal 单例

Android 中的 AnimationHandler 使用 ThreadLocal 单例

1
2
3
4
5
6
7
8
9
public class AnimationHandler {
    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
    public static AnimationHandler getInstance() {
        if (sAnimatorHandler.get() == null) {
            sAnimatorHandler.set(new AnimationHandler());
        }
        return sAnimatorHandler.get();
    }
}
本文由作者按照 CC BY 4.0 进行授权