1.适用场景
有一些对象,全局只能需要一个,例如线程池、缓存和注册表等,如果创建了好几个对象,那就麻烦大了。在举一个在开发中的例子,例如要构建一个音乐播放器,最好全局可以只有一个播放器的对象,这样,无论在程序的任何地方,都可以完成对同一变量的访问,整个程序的播放状态是统一的。
2. 如何构造(以MusicManager)
需要满足:1.全局只创建1个
2.随处可以访问
全局只创建一个,所以首先肯定想到不能随便的new,所以第一个想法就是将构造函数私有化,所以代码看起来会是这样子:
public class MusicManager{
//私有化构造函数
private MusicManager(){
}
}
问题来了:如何获取这个对象呢?
继续修改代码:
public class MusicManager{
private static MusicManager musicManager=null;
//私有化构造函数
private MusicManager(){
}
public static MusicManager getInstance(){
if(musicManager==null){
musicManager=new MusicManager();
}
return musicManager;
}
}
以上的代码就可以保证可以获得实例对象了~
但是这样就可以保证唯一了吗?
非也非也 假如该程序在两个线程中执行,看下图:
从上图可以看出,在多线程时候,无法保证只生成一个对象。
解决方法一
public class MusicManager{
private static MusicManager musicManager=new MusicManager();
//私有化构造函数
private MusicManager(){
}
public static MusicManager getInstance(){
return musicManager;
}
}
直接生成,这样就不怕访问的时候对象为空了,但问题在于,有些情况下,可能用不到这个实例对象,这个对象的实例又会消耗大量的资源,所以并不是一个很好的方法。
解决方法二
public class MusicManager{
private static MusicManager musicManager = null;
//私有化构造函数
private MusicManager(){
}
public static synchronized MusicManager getInstance(){
if(musicManager==null){
musicManager=new MusicManager();
}
return musicManager;
}
}
使用synchronized
关键字,这个关键字可以保证这个方法只有一个线程在操作,刚刚的问题自然迎刃而解,但是每次执行这个方法都要进行这个检验,十分的繁琐,消耗大量资源,因此并不是很推荐。
解决方法三(推荐)
public class MusicManager{
private static MusicManager musicManager = null;
//私有化构造函数
private MusicManager(){
}
public static MusicManager getInstance(){
if(musicManager==null){
synchronized (MusicManager.class){
if(musicManager==null){
musicManager=new MusicManager();
}
}
}
return musicManager;
}
}
先进行一个判空,只有当第一次执行时,才会进入里面加锁,之后的执行,直接返回对象即可,既可以满足要求,又节约资源,所以这是推荐的做法。