脚本宝典收集整理的这篇文章主要介绍了单例模式--还没从工厂中逃脱出来?看来是注定单身了..,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
上次我们聊了聊一个略微重量级的工厂模式,不知道你是否消化完从工厂中逃脱出来了呢?不是我说,今天的单例模式,恰恰好相反了,孤孤单单,看来是注定单身了..
在jdk中Runtime用到,饿汉式
1)饿汉式(静态常量) 2)饿汉式(静态代码块) 3)懒汉式(线程不安全) 4)懒汉式(线程安全,同步方法) 5)懒汉式(线程安全,同步代码块) 6)双重检查 7)静态内部类 8)枚举
非常勤快,在对象还没使用到的时候就先创建出来了
1)构造器私有化(防止new) 2)类的内部创建对象 3)向外暴露一个静态的公共方法 getInstance() 4)代码实现
public class Singleton1 {
PRivate Singleton1() {
}
private final static Singleton1 instance = new Singleton1();
public static Singleton1 getInstance(){
return instance;
}
}
1)优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。 2)缺点:在类装载的时候就完成实例化,没有达到LazyLoading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费 3)这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance就没有达到lazyloading的效果 4)结论:这种单例模式可用,可能造成内存浪费
优缺点跟上边是一样的,可以说是等效于上边的普通饿汉式
package com.melo.design.单例模式.饿汉式_静态代码块;
public class Singleton2 {
private Singleton2() {
}
private static Singleton2 instance ;
static {
instance = new Singleton2();
}
public static Singleton2 getInstance(){
return instance;
}
}
等到要用到了,再把对象创建出来
/**
* 懒汉式
* 线程安全
*/
public class Singleton {
//私有构造方法
private Singleton() {}
//在成员位置创建该类的对象
private static Singleton instance;
//对外提供静态方法获取该对象
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
实际上做不到线程同步,因为在if的时候就会出现线程混乱问题 比如if时A进来,B再进来,A先使用class,然后new了,B后续没有再次判断,还是会再次去new
刚好解决了上边懒汉式同步代码块的问题,再多一步if判断
package com.melo.design.单例模式.双检索;
public class Singleton {
//注意volatile修饰
private volatile static Singleton singleton;
private Singleton (){
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
在多线程的情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。 要解决双重检查锁模式带来空指针异常的问题,只需要使用 volatile 关键字, volatile 关键字可以保证可见性和有序性。
有关volatile相关的知识,目前还在整理,希望可以早点把并发和锁相关的知识一并整理出来
里边定义一个final静态常量 使用时直接返回静态内部类的final静态常量就好了!
public class Singleton {
//静态内部类,里边定义一个final静态常量
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
1)这种方式采用了类装载的机制来保证初始化实例时只有一个线程。 2)静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。 3)类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。 4)优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高 5)结论:推荐使用.
public enum StuUserService implements StuUserServiceinter {
/**
* 该类的唯一实例
*/
INSTANCE;
@override
public void test1(){
System.out.println("111");
}
public static void main(String[] args) {
StuUserService.INSTANCE.test1();
}
}
每一个枚举量看作是这个类的对象 同时可以设置成员变量,成员方法 然后可以根据成员变量设置相应的构造方法
私有化构造器并不保险。它抵御不了反射的攻击!!!
package com.melo.mydesign.单例模式.双检索;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
//开始搞事情
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//调用单例方法生成的对象1
Singleton singleton1 = Singleton.getSingleton();
//获得所有构造器(包括私有的)
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
//设置可访问
constructor.setAccessible(true);
//构造器生成
Singleton singleton2 = constructor.newInstance();
//判断是否相等,发现false,已然破坏了单例
System.out.println(singleton1==singleton2);
}
}
public static void main(String[] args) throws Exception {
Singleton s = Singleton.getInstance();
byte[] serialize = SerializationUtils.serialize(s);
Object deserialize = SerializationUtils.deserialize(serialize);
System.out.println(s);
System.out.println(deserialize);
System.out.println(s == deserialize);
}
Exception in thread "main" java.lang.NoSuchMethodException: com.fsx.bean.EnumSingleton.<inIT>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at com.fsx.maintest.Main.main(Main.java:19)
if ((clazz.getModifiers() & Modifier.ENUM) != 0){
throw new IllegalargumentException("Cannot reflectively create enum objects");
}
package com.melo.mydesign.单例模式.枚举;
import com.melo.mydesign.单例模式.双检索.Singleton;
import org.springframework.util.SerializationUtils;
public enum StuUserService implements StuUserServiceInter {
/**
* 该类的唯一实例
*/
INSTANCE;
@Override
public void test1(){
System.out.println("111");
}
public static void main(String[] args) {
// StuUserService.INSTANCE.test1();
StuUserService s = StuUserService.INSTANCE;
byte[] serialize = SerializationUtils.serialize(s);
Object deserialize = SerializationUtils.deserialize(serialize);
System.out.println(s);
System.out.println(deserialize);
System.out.println(s == deserialize);
}
}
懒汉式: 用到了再来创建对象(就得加锁,判断是不是null,是null得加锁才来生成,防止多次实例化) 饿汉式(比较勤快):类加载时就先生产好了对象,保证了线程安全,但浪费了内存空间
以上是脚本宝典为你收集整理的单例模式--还没从工厂中逃脱出来?看来是注定单身了..全部内容,希望文章能够帮你解决单例模式--还没从工厂中逃脱出来?看来是注定单身了..所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。