单例模式(Singleton Pattern)属于创建型模式,它提供了一种创建单一对象的方式。
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常,我们在new一个对象时,不能防止它被实例化多次,怎样保证它只被实例化一次呢,一个最好的办法就是让这个类自身去创建并保存它的唯一实例,再提供一个访问该实例的公共方法,那么就能保证它被实例化一次了。
在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作。
Singleton也能够被无状态化。提供工具性质的功能。
在被引用时才会实例化自己
public class Singleton1 {
private static Singleton1 instance;
//构造方法私有化,防止外界利用new创建此实例的可能
private Singleton1(){
}
public static Singleton1 getInstance(){
if(instance == null){
instance = new Singleton1();
}
return instance;
}
}
public class Singleton {
private static Singleton singleton= new Singleton();
private singleton() {
}
public static Singleton newInstance() {
return singleton;
}
}
饿汉式示例虽然用延迟加载方式实现了懒汉式单例,但在多线程环境下会产生多个singleton对象
优化后??????????????????
public class Singleton3 {
// 私有构造
private Singleton3() {}
private static Singleton3 single = null;
public static Singleton3 getInstance() {
// 等同于 synchronized public static Singleton3 getInstance()
synchronized(Singleton3.class){
// 注意:里面的判断是一定要加的,否则出现线程安全问题
if(single == null){
single = new Singleton3();
}
}
return single;
}
}
这个是懒汉形式的加强版,将synchronized关键字移到了newInstance方法里面,同时将singleton对象加上volatile关键字,这种方式既可以避免多线程问题,又不会降低程序的性能。但volatile关键字也有一些性能问题,不建议大量使用。
使用双重检查进一步做了优化,可以避免整个方法被锁,只对需要锁的代码部分加锁,可以提高执行效率。
public class Singleton4 {
// 私有构造
private Singleton4() {}
private static Singleton4 single = null;
// 双重检查
public static Singleton4 getInstance() {
if (single == null) {
synchronized (Singleton4.class) {
if (single == null) {
single = new Singleton4();
}
}
}
return single;
}
}
这里创建了一个内部静态类,通过内部类的机制使得单例对象可以延迟加载,同时内部类相当于是外部类的静态部分,所以可以通过jvm来保证其线程安全。这种形式比较推荐。
public class Singleton4 {
// 私有构造
private Singleton4() {}
private static Singleton4 single = null;
// 双重检查
public static Singleton4 getInstance() {
if (single == null) {
synchronized (Singleton4.class) {
if (single == null) {
single = new Singleton4();
}
}
}
return single;
}
}
public enum Singleton {
singleton
}
public class SingletonFactory {
// 内部枚举类
private enum EnmuSingleton{
Singleton;
private Singleton8 singleton;
//枚举类的构造方法在类加载是被实例化
private EnmuSingleton(){
singleton = new Singleton8();
}
public Singleton8 getInstance(){
return singleton;
}
}
public static Singleton8 getInstance() {
return EnmuSingleton.Singleton.getInstance();
}
}
class Singleton8{
public Singleton8(){}
}
使用Singleton注意事项:
有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器,跨JVM的。
Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java的类 线程 内存等概念有相当的了解。
Java设计模式之单例模式详解
单例模式的5种形式