设计模式

单例

  • 单例:在一个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.获得方法
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 什么是设计模式? 是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。一些开发的套路,用于解决某一些特...
    Spring618阅读 656评论 0 0
  • 阅读原文 在介绍单例模式之前,我们先了解一下,什么是设计模式?设计模式(Design Pattern):是一套被反...
    gyl_coder阅读 154评论 0 3
  • 锡马破三,乃知厚积而能薄发。世事如棋,参悟几何,乃知慎勿轻速、动须相应的道理。 下围棋的人都知道“...
    Smiler_918c阅读 1,620评论 0 0
  • 从博物馆出来已是大中午了,我本想打个车,妈妈感慨赚钱不易,非要坐公交。 一人一元钱,空调车,我感慨这边的公交非常实...
    苏_8ab1阅读 238评论 0 2
  • 替换及重置Homebrew默认源 在中科大源失效或宕机时可以: 1. 使用清华源设置参考。 2. 切换回官方源: ...
    Devid阅读 1,735评论 0 3