只看理论就是一看而过了,也不能真正理解,敲一下吧
- package pratice716;
- public class Singleton {
- /**
- * 懒汉式-线程不安全
- * 私有静态变量 uniqueInstance 被延迟实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。
- * 多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,那
- * 么会有多个线程执行 uniqueInstance = new Singleton(); 语句,这将导致实例化多次 uniqueInstance。
- */
- private static Singleton uniqueInstance;
- private Singleton(){
- }
- public static Singleton getUniqueInstance(){
- if(uniqueInstance == null){
- uniqueInstance = new Singleton();
- }
- return uniqueInstance;
- }
- //2直接实例化,饿汉式,线程安全,不节约资源
- private static Singleton uniqueInstance2 = new Singleton();
- //2懒汉式-线程安全,对方法进行加锁.即使已被实例化,有线程进入,其他都等待,阻塞严重。不推荐
- public static synchronized Singleton getUniqueInstance2(){
- if(uniqueInstance == null){
- uniqueInstance = new Singleton();
- }
- return uniqueInstance;
- }
- //3双重校验锁-线程安全:只需被实例化一次,加锁只对公有静态函数,先判断是否实例,木有实例才对实例化加锁
- /*
- * 只使用了一个 if 语句。在 uniqueInstance == null 的情况下,如果两个线程都执行了 if 语句,
- * 那么两个线程都会进入 if 语句块内。虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton();
- * 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,也就是需要使用两个 if 语句:第一个 if
- * 语句用来避免 uniqueInstance 已经被实例化之后的加锁操作,而第二个 if 语句进行了加锁,所以只能有一个线程进入,
- * 就不会出现 uniqueInstance == null 时两个线程同时进行实例化操作。
- */
- private static Singleton uniqueInstance3;
- public static Singleton getUniqueInstance3(){
- //使用双重if语句才能保证不能两次实例化
- if(uniqueInstance == null){
- synchronized(Singleton.class){
- if(uniqueInstance == null){
- uniqueInstance = new Singleton();
- }
- }
- }
- return uniqueInstance;
- }
- //4禁止JVM的分配内存空间、初始化、指向分配的内存地址指令重排,保证多线程下正常运行.
- //4实例化采用volatile
- private volatile static Singleton uniqueInstance4;
- /*
- * 静态内部类
- * 静态内部类只有调用对应方法才会被加载,实例也是一次,延迟初始化,线程安全
- */
- private static class SingletonH{
- private static final Singleton IN = new Singleton();
- }
- public static Singleton getUniqueInstence(){
- return SingletonH.IN;
- }
- }
枚举:
- package pratice716;
- //枚举实现,enum的全称为 enumeration, 是 JDK 1.5中引入的新特性,存放在 java.lang包中。
- /*
- * 创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类
- * (java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum<E extends Enum<E>>,
- * 而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal)
- * 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。
- */
- public enum Singleton1{
- IN;
- private String obj;
- public String getobj(){
- return obj;
- }
- public void setobj(String obj){
- this.obj = obj;
- }
- public static void main(String args[])
- {
- //单例测试
- Singleton1 first = Singleton1.IN;
- first.setobj("first");
- System.out.println("first: "+first);
- Singleton1 second = Singleton1.IN;
- second.setobj("second");
- System.out.println("first: "+first);
- System.out.println("second: "+second);
- //反射获取实例
- try {
- Singleton[] enumConstants = Singleton.class.getEnumConstants();
- for (Singleton enumConstant : enumConstants) {
- System.out.println(enumConstant.getObj());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * 该实现可以防止反射攻击。在其它实现中,通过 setAccessible() 方法可以将私有构造函数的访问级别设置为 public,
- * 然后调用构造函数从而实例化对象,如果要防止这种攻击,需要在构造函数中添加防止多次实例化的代码。该实现是由 JVM 保证只
- * 会实例化一次,因此不会出现上述的反射攻击。
- * 该实现在多次序列化和序列化之后,不会得到多个实例。而其它实现需要使用 transient 修饰所有字段,并且实现序列化和反序列化的方法。
- */
- }
扫码关注一起随时随地学习!!!就在洋葱攻城狮,更多精彩,等你来!!