Java育儿园约架专栏

设计模式

2019-10-14  本文已影响0人  磨陀货_

单例

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

/**
 * 饿汉----- 不能按需加载,可能会造成资源浪费
 */
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;
    }
}


目前存在的问题:

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的区别

动态代理


/**
 * 实现了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.获得方法
上一篇 下一篇

猜你喜欢

热点阅读