java基础3

1.死锁
  • 死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程

  • 条件:

    1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
    2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
    3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
    4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。

  • 避免
    死锁避免的基本思想:系统对进程发出每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略

    打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。

    打破不可抢占条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。

    打破占有且申请条件:采用资源预先分配策略,即进程运行前申请全部资源,满足则运行,不然就等待,这样就不会占有且申请。

    打破循环等待条件:实现资源有序分配策略,对所有设备实现分类编号,所有进程只能采用按序号递增的形式申请资源。

2.类加载过程
image.png
3.synchronized底层实现原理

https://blog.csdn.net/javazejian/article/details/72828483

4.synchronized与Lock的区别
  • 1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;

  • 2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;

  • 3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;

  • 4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;

  • 5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)

  • 6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

5.反射
  • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
  • 1.获取反射中的class对象
    1).使用Class.forName静态方法,知道类的全路径名
Class c1 = Class.forName(“java.lang.String”);

2).直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高

Class c2 = String.class;

3).通过对象调用 getClass() 方法来获取,通常应用于不知道具体是什么类

String str = new String("Hello");
Class c3 = str.getClass();
  • 2.通过反射创建类对象
    1).通过 Class 对象的 newInstance() 方法。
Class clz = Phone.class;
Phone phone = (Phone)clz.newInstance();

2).通过 Constructor 对象的 newInstance() 方法

Constructor constructor = clz.getConstructor();
Phone phone= (Phone)constructor.newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法

Class clz = Phone.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Phone phone = (Phone) constructor.newInstance("华为",6666);
  • 3.通过反射获取类属性、方法、构造器

    getName():获得类的完整名字。
    getFields():获得类的public类型的属性。
    getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
    getMethods():获得类的public类型的方法。
    getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
    getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
    getConstructors():获得类的public类型的构造方法。
    getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。

6.java序列化
  • 序列化:将 Java 对象转换成字节流的过程。

  • 反序列化:将字节流转换成 Java 对象的过程。

  • 当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。

  • 序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。

  • 注意事项:

某个类可以被序列化,则其子类也可以被序列化
声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据
反序列化读取序列化对象的顺序要保持一致

7.动态代理
  • 代理模式:代理模式给一个对象提供一个代理对象,并由代理对象控制对原对象的引用
  • 动态代理:方便运行时动态构建代理、动态处理代理方法调用的机制。实现方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情,甚至根本不去执行这个方法,因为在InvocationHandler的invoke方法中,可以直接获取政治调用方法对应的Method对象,具体应用的话,可以添加调用日志,做事务控制等。例如商户---->明星经纪人(代理)---->明星
java动态代理
  • Java的动态代理是基于java.lang.reflect.Proxy、java.lang.reflect.invocationHandler两个类来完成的,使用了反射机制,基于接口。
  • 动态代理和静态代理的区别在于静态代理我们需要手动的去实现目标对象的代理类(编译时确定被代理的类时哪一个),而动态代理可以在运行期间动态的生成代理类。
  • newProxyInstance()
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

newProxyInstance方法用来返回一个代理对象,这个方法总共有3个参数:
ClassLoader loader用来指明生成代理对象使用哪个类装载器;
Class[] interfaces用来指明生成哪个对象的代理对象,通过接口指定;
InvocationHandler h用来指明产生的这个代理对象要做什么事情。
所以我们只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。

  • InvocationHandler中的invoke()方法
public Object invoke(Object proxy,Method method,Object args){
method.invoke();
}

proxy:代理对象
method:代理对象调用的方法
args:方法参数

cglib动态代理
  • 通过“继承”可以继承父类所有的公开方法,然后可以重写这些方法,在重写时对这些方法增强,这就是cglib的思想。根据里氏代换原则(LSP),父类需要出现的地方,子类可以出现,所以cglib实现的代理也是可以被正常使用的。
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Cglib动态代理,监听开始!");
        Object invoke = method.invoke(代理对象,参数数组);
        System.out.println("Cglib动态代理,监听结束!");
        return invoke
 }
//定义获取代理对象方法
    public Object getCglibProxy(Object objectTarget){
        //为目标对象target赋值
        this.target = objectTarget;
        Enhancer enhancer = new Enhancer();
        //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(objectTarget.getClass());
        enhancer.setCallback(this);// 设置回调 
        Object result = enhancer.create();//创建并返回代理对象
        return result;
    }
8.克隆
  • 想对一个对象进行处理,又想保留原有的数据进行接下来的操作,就需要克隆,java语音中克隆针对的是类的实例

  • 浅克隆(shallowclone)和深克隆(deepclone)

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
1.被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常), 该接口为标记接口(不含任何方法)
2.覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。(native为本地方法)


image.png

深克隆不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。


image.png
  • 也可以通过BeanUtils和PropertyUtils进行对象复制
  • 通过序列化实现对象的复制

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

你可能感兴趣的:(java基础3)