如何实现一个线程安全的单例,前提是不能加锁?
利用CAS(Compare And Swap)来实现无锁的单例。
用CAS的好处在于不需要使用传统的锁机制来保证线程安全,CAS是一种基于忙等待的算法,依赖底层硬件的实现,相对于锁它没有线程切换和阻塞的额外消耗,可以支持较大的并行度。
CAS的一个重要缺点在于如果忙等待一直执行不成功(一直在死循环中),会对CPU造成较大的执行开销。另外,如果N个线程同时执行到singleton = new Singleton();的时候,会有大量对象创建,很可能导致内存溢出。
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();
private Singleton() {
}
public static Singleton getInstance() {
for (; ; ) {
Singleton singleton = INSTANCE.get();
if (null != singleton) {
return singleton;
}
singleton = new Singleton();
if (INSTANCE.compareAndSet(null, singleton)) {
return singleton;
}
}
}
//test
public static void main( String[] args ) throws Exception{
Singleton singleton= Singleton.getInstance();
Singleton singleton2= Singleton.getInstance();
System.out.printf("singleton == singleton2 ? %s\n",singleton==singleton2);
Test test=new Test();
Test test2=new Test();
ExecutorService executor= Executors.newFixedThreadPool(2);
executor.execute(test);
executor.execute(test2);
Thread.sleep(1000);
Singleton singleton3=test.getValue();
Singleton singleton4=test2.getValue();
System.out.printf("singleton3 == singleton4 ? %s\n",singleton3==singleton4);
System.out.printf("singleton2 == singleton4 ? %s",singleton2==singleton4);
}
}
class Test implements Runnable{
private Singleton singleton;
@Override
public void run() {
singleton=Singleton.getInstance();
}
public Singleton getValue(){
return singleton;
}
运行结果
singleton == singleton2 ? true
singleton3 == singleton4 ? true
singleton2 == singleton4 ? true