单例模式
单例模式:确保一个类只有一个实例,并提供一个全局访问点。
单例模式的实现:
1.
public class Singleton {
private static Singleton uniqueSingleton;
//私有构造器
private Singleton(){}
//需要时才实例化对象()
public static Singleton getInstance(){
if (uniqueSingleton == null){
uniqueSingleton = new Singleton();
}
return uniqueSingleton;
}
}
采用这种方式实现单例模式,创建多线程时可能会出现意想不到的问题。如下图所示:
因此我们可以选择第二种方式。
2.
public class Singleton {
//在类加载时就实例化对象
private static Singleton uniqueSingleton = new Singleton();
//私有构造器
private Singleton(){}
public static Singleton getInstance(){
return uniqueSingleton;
}
}
在类加载时实例化对象就不会发生上图所示错误。
3.
为了防止多线程问题,还可以采取双重检查加锁方式,使用volatile和synchronized关键字
/**
* 双重检查,解决了线程安全问题
* 同时保证了效率,推荐使用
*/
public class SingletonTest03 {
public static void main(String[] args){
//测试
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1==instance2);
System.out.println("instance1.hashCode()="+instance1.hashCode());
System.out.println("instance2.hashCode()="+instance2.hashCode());
}
}
class Singleton{
//volatile关键字(还没学过)
private static volatile Singleton instance;
private Singleton(){
}
//synchronized关键字
//双重检查,解决线程安全问题
public static Singleton getInstance(){
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4.
通过静态内部类方式实现
/**
*这种方式避免了线程不安全,实现了延迟加载,效率高
* 推荐使用
*/
public class SingletonTest04 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println("instance1.hashCode()="+instance1.hashCode());
System.out.println("instance2.hashCode()="+instance2.hashCode());
System.out.println(instance1.getClass());
System.out.println(instance2.getClass());
}
}
class Singleton {
//构造器私有化
private Singleton(){}
//声明一个静态内部类,该类中有一个静态属性
//加载外部类时不会加载静态内部类,所以可以实现延迟加载
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
5.
通过枚举方式实现
/**
* 借用枚举来实现单例模式,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
* 这种方式是Effective Java作者推荐使用的方式
*/
public class SingletonTest05 {
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
instance1.sayOk();
}
}
//使用枚举,同样可以实现单例
enum Singleton{
INSTANCE;//属性
void sayOk(){
System.out.println("ok~~~~~");
}
}