设计模式

作者: 磨陀货_ | 来源:发表于2019-10-14 14:54 被阅读0次

单例

  • 单例:在一个java进程中保存一个实例

饿汉----- 不能按需加载,可能会造成资源浪费

/**
 * 饿汉----- 不能按需加载,可能会造成资源浪费
 */
public class Singleton01 {
    private static final Singleton01 SINGLETON_01 = new Singleton01();
    private  Singleton01(){}
    private static Singleton01 getSingleton01(){
        return SINGLETON_01;
    }
}

懒汉----判断一下,用到的时候在创建,延时加载

/**
 * 懒汉----延迟加载
 */
public class Singleton02 {
    private static Singleton02 SINGLETON_01;
    private Singleton02(){}
    private static Singleton02 getSingleton01(){
        if (SINGLETON_01 == null)SINGLETON_01 = new Singleton02();
        return SINGLETON_01;
    }
}

线程问题。加锁
synchronizaed---效率问题(这里只有null才用等待,但是synchronizaed是全等待)

/**
 * 懒汉--- 在方法上加synchronized ,可以保证线程安全,但是效率是很大问题
 * 因为下方代码,只有为null的时候才有必要等待,但是这样任何情况都要等待,锁太多了
 */
public class Singleton03 {
    private static Singleton03 SINGLETON_01;
    private Singleton03(){}
    private static synchronized Singleton03 getSingleton01(){
        if (SINGLETON_01 == null)SINGLETON_01 = new Singleton03();
        return SINGLETON_01;
    }
}

  • 这里我们未解决上面问题,把锁的位置进行改变,但是并不完美,还是有可能出问题


    会出现new多次

  • 最后衍生出这种比较好的方式。接着往下看


    解决线程安全问题

目前存在的问题:

1.问题一:指令重排序(JVM会在不影响代码最终逻辑的情况下,按照自己最优的方式执行)

当第一个线程A走到new执行时,线程B来了会直接判断不为空,直接返回

2.问题二(JMM内存模型,引起线程可见性)

共享变量和私有变量转换问题 多个读取,导致最后读取结果不一样
  • 解决问题:  加关键字 volatile
    1.防止指令重排序(某个变量加了volatile,就可以保证前面代码一定执行结束在执行他,他之后的代码一定是在他之后执行)
    2.保证线程可见性 (线程A 进行修改,就会强制使线程B实现【必须要再次从主存中读取】线程B改变了,线程A或者其他的都失效了)
    3.不保证原子性(下面图片)
    怎么就不保证原子性了,案例
public class VoilatileTest {
    private static volatile  int i =0;
    private static void incr (){
        i++;
    }
    public static void test(){
        for (int j=0;j<100;j++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int k=0;k<100;k++)incr();
                }
            }).start();
        }
    }
    public static void main(String[] args) {
        test();
        //当前存活的线程 除了主线程
        // 精灵线程(守护线程):随着守护的线程出生而出生,随着守护的线程死亡而死亡 垃圾回收
        //在正常结束程序finally是否一定执行,不一定,在守护线程中
        while (Thread.activeCount()>2){
            //礼让 让别的线程先执行
            Thread.yield();
        }
        System.out.println(i);
    }
}

运行结果是不定的,可能是10000,也可能是9998,9999,9993,9994等等。原因就是volatile不能保证原子性


这里为什么大于2,在JVM永远存在一个守护线程,随着守护的线程出生而出生。随着守护的线程死亡而死亡(垃圾回收)

所以就没有什么完美的解决方案,都是在项目中针对情况而定。需要哪种方式就用哪种。

Thread.currentThread()--- 获取当前线程


  • 在正常结束程序 finally 是否一定执行?【不一定,在守护线程中】

volatile与synchronized的区别

  • volatile可以解决可见性、防止指令重排序,但是有缺点就是不保证原子性,在高并发的情况下,会出现错误,使用时要针对情况来定是否使用
  • synchronized很强大,可以解决volatile的不保证原子性问题,但是效率很低。锁都可以解决,只是考虑效率问题,使用也是看情况定

动态代理

  • 1.通过 jdk实现
  • 2.通过cglib实现
    spring两种都有,如果有接口就用jdk,如果没有就用cglib。也可以强制使用cglib

/**
 * 实现了InvocationHandler 接口的类才有jdk代理功能
 */
public class DaiLiProxy implements InvocationHandler{
    private DaiLiTest daiLiTest;
    public DaiLiProxy( DaiLiTest daiLiTest){
        this.daiLiTest = daiLiTest;
    }
    public Object getInstance(){
        //类加载器 就用被代理对象的类加载器
        //被代理对象实现接口
        //能实现代理功能的对象
        return  Proxy.newProxyInstance(daiLiTest.getClass().getClassLoader(),
                daiLiTest.getClass().getInterfaces(),
                this);
    }
    //method就代表你调用的方法 在我们这儿就代表show方法
    //proxy代表的就是代理对象
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke方法被调用了");
        System.out.println("开启事务");
        try {
            //真正执行被代理对象的方法
            method.invoke(daiLiTest, null);
            System.out.println("提交事务");
        }catch (Exception e){
            System.out.println("回滚事务");
        }
        return null;
    }
    public static void main(String[] args) {
        //被代理对象
        DaiLiTest daiLiTest = new DaiLiTest();
        DaiLiProxy daiLiProxy = new DaiLiProxy(daiLiTest);
        //获得代理对象
        IDaiLi instance = (IDaiLi)daiLiProxy.getInstance();
        instance.show();
    }
}
public interface IDaiLi {
    void show();
}
public class DaiLiTest implements IDaiLi{
    public void show(){
        System.out.println("明天休息");
        throw new RuntimeException("出现异常");//不加这异常,得到结果图一。加上的到结果图二
    }
}

图一



图二



工厂模式

反射 -- Reflect

动态的时候可以获取他的信息,进行修改


1.获得class对象(3种)

实体类.class   new 实体类().getClass();   Class.forName("实体类完全限定名");

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnno {
    String value() default "";
}
@TestAnno("中午吃什么啊?")
public class Student {
    private String name;
    public Student(String name) {this.name = name;}
    public Student(){}
    public String getName() {return name;}
    private String show(String sos,int i){
        System.out.println(name+"show一波:"+sos+"  "+i);
        return "返回值呗拿到了";
    }
}
public class ReflectTest {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        Class<Student> studentClass = Student.class;//1.获得class对象
        Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor();//获得构造方法
        declaredConstructor.setAccessible(true);//无论是属性,构造方法,方法 只要是私有都需要设置可进入
        Student student = declaredConstructor.newInstance();//创建student对象
        System.out.println(student);//reflect.Student@1540e19d

        TestAnno annotation = studentClass.getAnnotation(TestAnno.class);//获得单个注解
        String value = annotation.value();
        System.out.println(value);//中午吃什么啊?

        //获得所有注解
        Annotation[] annotations = studentClass.getAnnotations();
        for (Annotation annotation1 : annotations) {
            System.out.println(annotation1);//@reflect.TestAnno(value=中午吃什么啊?)
        }
        //判断是否有某个注解
        boolean annotationPresent = studentClass.isAnnotationPresent(TestAnno.class);
        System.out.println(annotationPresent);//true

        //获得属性
        Field name = studentClass.getDeclaredField("name");
        name.setAccessible(true);
        //改值  肯定得依赖对象存在
        name.set(student,"abc");
        System.out.println(student.getName());//abc

        //获得方法
        Method method = studentClass.getDeclaredMethod("show", String.class, int.class);
        method.setAccessible(true);
        Object result = method.invoke(student, "跳舞", 10);
        System.out.println(result);//abcshow一波:跳舞  10            //返回值呗拿到了
    }
}

2.获得构造方法

``


3.获得注解
获得单个注解 获得所有注解 判断是否有某个注解
4.获的属性
获得属性

懒汉防止不了反射攻击,懒汉final修饰,反射还是可以改值。
饿汉就可以防止反射,饿汉加上final修饰,反射就攻击不了。


5.获得方法

相关文章

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 设计模式笔记汇总

    目录 设计原则 “依赖倒置”原则 未完待续... 设计模式 设计模式——策略模式 设计模式——装饰者模式 设计模式...

  • 设计模式

    《C#设计模式》 《C#设计模式》-设计模式概述 《C#设计模式》-面向对象设计原则 《C#设计模式》-单例模式 ...

  • 浅谈JS的一些设计模式

    @(书籍阅读)[JavaScript, 设计模式] 常见设计模式 设计模式简介 设计模式概念解读 设计模式的发展与...

  • 前端设计模式

    JS设计模式一:工厂模式jS设计模式二:单例模式JS设计模式三:模块模式JS设计模式四:代理模式JS设计模式五:职...

  • 设计模式之工厂模式

    设计模式之工厂模式 标签(空格分隔): 设计模式 工厂模式 设计模式的感念 设计模式的应用 工厂设计模式的产生 工...

  • JavaJavascript基础进阶(十七)JS中常用的设计模式

    单利设计模式、构造原型设计模式、发布订阅设计模式、promise设计模式 单利模式 构造原型设计模式 最贴近OOP...

  • 设计模式 - 目录

    设计模式01 - 单例模式 设计模式02 - 工厂模式 设计模式03 - 建造者模式 设计模式04 - 适配器模式...

  • 第1章 设计模式概述

    一、设计模式的概念 二、设计模式的历史 三、设计模式的要素 四、设计模式的分类 ■ 创建型设计模式 ■ 结构型设计...

  • iOS设计模式(3)适配器模式

    设计模式系列文章 《iOS设计模式(1)简单工厂模式》《iOS设计模式(2)工厂模式》《iOS设计模式(4)抽象工...

网友评论

    本文标题:设计模式

    本文链接:https://www.haomeiwen.com/subject/ayifmctx.html