定义:
确保某一个类只有一个实例,而且自动实例化并向整个系统提供这个实例。
代码:
Singleton类称为单例类,通过使用private的构造函数确保了在一个应用中只产生一个实例,并且是自行实例化的。
class="java" name="code">/** * 线程安全的单例模式 * 饿汉式单例 * @author Administrator * */ public class Singleton { private static final Singleton singleton = new Singleton(); // 限制产生多个对象 private Singleton() { } // 通过该方法获得实例对象 public static Singleton getSingleton() { return singleton; } // 类中其他方法尽量是static public static void doSomething() { } }
?
单例模式的优点:
?
单例模式的缺点:
?
单例模式的使用场景:
?
单例模式的注意事项:
? 1.? 在高并发情况下,请注意单例模式的线程同步问题。
/** * 懒汉式单例 * @author Administrator * */ public class Singleton2 { private static Singleton2 singleton = null; // 限制产生多个对象 private Singleton2() { } // 通过该方法获得实例对象 public static Singleton2 getSingleton() { synchronized (singleton) { if (singleton == null) { singleton = new Singleton2(); } } return singleton; } }
?
如果不加synchronized进行控制,如果第一个线程A执行到singleton = new Singleton2(),但还没有获得对象,第二个线程B也在执行,执行到if (singleton == null)判断,那么线程B获得判断条件为真,于是继续运行下去,线程A和B都获得了对象,内存中就出现了两个对象。
建议使用饿汉式单例,那是线程安全的单例模式。
?
? 2.? 需要考虑对象的复制情况。在Java中,若实现Cloneable接口,并实现了clone方法,则可以直接通过对象复制方式创建一个新对象,对象复制是不用调用类的构造函数的。
?
? 3.? 注意JVM的垃圾回收机制,如果我们的一个单例对象在内存中长久不使用,JVM就认为这是一个垃圾对象,在CPU资源空闲的情况下该对象会被清理掉,下次再调用时就需要产生一个新对象。如果该对象作为有状态值的管理,则会出现状态恢复原状的情况,就会出现故障。
有两种方法可以解决该问题?
单例模式的扩展:
能产生固定数量实例的单例模式
/** * 能产生固定数量实例的单例模式 * @author Administrator * */ public class Singleton3 { // 最多能产生的实例数 private static int maxNumOfSingleton = 2; // 定义一个列表,容纳所有实例 private static ArrayList<Singleton3> singletonList = new ArrayList<Singleton3>(); // 产生所有对象 static { for (int i = 0; i < maxNumOfSingleton; i++) { singletonList.add(new Singleton3()); } } // 限制其他类生成对象 private Singleton3() { } // 随机获得一个实例 public static Singleton3 getInstance() { Random random = new Random(); return singletonList.get(random.nextInt(maxNumOfSingleton)); } }
?在SSH中的运用
1.hibernate 中
我们知道Session是由SessionFactory负责创建的,而SessionFactory的实现是线程安全的,采用前面提到的“饿汉模式”创建单例。多个并发的线程可以同时访问一个SessionFactory并从中获取Session实例,那么Session是否是线程安全的呢?很遗憾,答案是否定的。Session中包含了数据库操作相关的状态信息,那么说如果多个线程同时使用一个Session实例进行CRUD,就很有可能导致数据存取的混乱,你能够想像那些你根本不能预测执行顺序的线程对你的一条记录进行操作的情形吗?以上代码使用ThreadLocal模式的解决了这一问题。 只要借助上面的工具类获取Session实例,我们就可以实现线程范围内的Session共享,从而避免了线程中频繁的创建和销毁Session实例。当然,不要忘记在用完后关闭Session。?2.spring中
项目加载的时候bean(一个bean对应某个类)自动创建(初始化,建一个实例),而后是每次调用bean的时候是注入的(不是重新new。。所有整个系统都是这个实例,,而且是spring自动提供的)?3.struts
" Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。关注微信公众账号: 快乐编程? ,一起交流技术知识,享受快乐编程!