总结了两个经典的懒加载单例模式
先上代码:
这是EventBus中的代码。
如果直接给方法加上synchronized。所有getInstance()的调用都要同步了。其实我们只是在第一次new对象的时候要同步。而同步需要消耗性能
上述代码除了有两次检查instance == null,另一个特点是变量instance的类型声明中添加了volatile,因为像下面这种创建对象的语句并不是原子操作,volatile可以使其成为原子操作,避免同步问题。
虽说部分JVM没有完全volatile,但是目前主流的JVM貌似已经都支持了,所以这个问题一般可以忽略。
另外推荐一个更好的简洁方法:
使用静态内部类。
public class OssClient { //log private Logger logger = LoggerFactory.getLogger(this.getClass()); //阿里云API的内或外网域名 private static String END_POINT; //阿里云API的密钥Access Key ID private static String ACCESS_KEY_ID; //阿里云API的密钥Access Key Secret private static String ACCESS_KEY_SECRET; //阿里云API的BUCKET_NAME private static String BUCKET_NAME; public static class clientSingletonHolder{ //init on demand static OSSClient client = new OSSClient(END_POINT,ACCESS_KEY_ID, ACCESS_KEY_SECRET); } /** * 获取阿里云OSS客户端对象 * */ public OSSClient getOSSClient(){ return clientSingletonHolder.client; }}
解释一下,因为java机制规定,内部类clientSingletonHolder只有在getOSSClient()方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的(实现线程安全)。内部类加载的时候实例化一次client 。