单例模式(Singleton Pattern)
单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供一个全局访问点。
某些对象我们只需要一个,比如线程池、缓存、注册表等等。如果这些类拥有多个实例,可能会产生很多问题。
使用单例模式可以确保我们使用的这些全局资源只有一份。
一个经典的单例模式的实现:
- public class Singleton{
- private static Singleton uniqueInstance;
- private Singleton(){}
- public static Singleton getInstance(){
- if(uniqueInstance==null){
- uniqueInstance=new Singleton();
- }
- return uniqueInstance;
- }
- }
这样就确保了单例的类最多只能有一个实例。
多线程下的隐患
在多线程的情况下,如果两个线程几乎同时调用getInstance()方法会发生什么呢?有可能会创建出两个该类的实例。
我们可以将getInstance()方法变为同步方法来解决这个问题:
- public class Singleton{
- private static Singleton uniqueInstance;
- private Singleton(){}
- public static synchronized Singleton getInstance(){
- if(uniqueInstance==null){
- uniqueInstance=new Singleton();
- }
- return uniqueInstance;
- }
- }
然而,事实上,我们只有在uniqueInstance为null的时候才需要进行同步,当这个类已经有实例之后就不存在多线程隐患了。
因此我们将getInstance()方法变为同步方法有可能很大程度的拖垮性能。
如果将getInstance()方法变为同步方法真的影响到了性能,我们可以选择在静态初始化时创建这个单例。
- public class Singleton{
- private static Singleton uniqueInstance=new Singleton();
- private Singleton(){}
- public static Singleton getInstance(){
- return uniqueInstance;
- }
- }
问题是,前面的例子中都是在需要一个实例的时候在创建单例,这个例子中在类初始化时就创建了单例。如果这个对象非常耗资源,而程序中又一直没有用到它,这样便是在浪费资源了。
“双重检查加锁”
- public class Singleton{
- private volatile static Singleton uniqueInstance;//volatile修饰被不同线程访问和修改的变量
- private Singleton(){}
- public static Singleton getInstance(){
- if(uniqueInstance==null){
- synchronized(Singleton.class){//对整个类加锁
- if(uniqueInstance==null){
- uniqueInstance=new Singleton();
- }
- }
- }
- return uniqueInstance;
- }
- }
评论暂时关闭