16-20
双亲委派向下查找
bootstrap class loader
extclassloader
app classloader
向上委派:实际上就是查找缓存,看是否已经加载了该类,有的话就直接缓存,没有的话就继续向上委派。
委派到顶层bootstrap class loader,如果还是没有的话就到加载路径(有这个jar包但是还没有加载进去)中查找有就返回没有就向下查找,查到最低层还是没有的话就说明没有这个类,就返回没有提示。
双亲委派模型的优点:
安全性,避免用户自己编写类动态来替换Java中的核心类,用户自己写的类不能是以Java.开头大的,比如String
同时为了避免类的重复加载,因为jvm中区分不同的类,不仅仅是根据类名,相同的class文件被不同的classloader加载就是不同的两个类。
Java中的异常体系
所有异常都来自顶级父类throuable
下面有两个子类exception和error
error是程序无法处理的错误,一旦出现错误那么程序就会终止。
excepetion不会导致程序停止,分为runtimeexception运行时异常和checkexception检查异常。
runtimeexception导致程序当前线程执行失败,checkedexception常常发生在编译过程出现,但是idea会自己发现。一般程序员不需要过多的关注
gc(垃圾处理器)如何判断哪些对象可以回收
引用计数法,每一个对象有一个引用计数属性,新增一个引用时计数器+1,引用释放时-1,引用为0可以被回收,Java不采用,但是python采用。
引用计数法的弊端:可能会出现A引用B,B又引用了A,那么这两个都无法被使用但是计数器又不为0所以无法被回收。
可达性分析:从Gc root开始向下搜索,搜索所走过的路径成为引用链,当一个对象没有一个引用恋是,就说明这个对象是不可用的,那么虚拟机判断他为可回收对象回收他。
gc roots的对象有:
1.虚拟机栈中引用的对象
2.方法区中类静态属性所引用的对象
3.常量引用的对象
4.本地方法native方法引用的对象。
可达性算法中不可达对象并不是立即死亡的,对象拥有一次自我拯救的机会,,对象被系统回收至少经历两次标记过程
第一次是经过可达性分析发现没有跟gc root链接的引用恋,第二次是在虚拟机自动建立的finalizer队列中判断是否需要执行finalizd()方法。
当对象gc root不可达时,gc就会判断对象是否覆盖finallize方法如果没有覆盖那么就直接回收,否则若对象没有执行过finallized方法将其放入f-queue队列之中,执行finallize()方法。执行过后gc会再次判断是否可达如果不可达就进行回收,如果可达就不进行回收。(一般就是说finallize方法里面被改写了,会产生其他的引用),但是finallize方法运行成本比较高,一般来说不会轻易去覆盖这个方法。
线程的生命周期,线程有哪些状态
创建,就绪,运行,阻塞,死亡
阻塞:
1等待阻塞wait方***释放所有的资源,包括锁资源,不能够自动唤醒,必须要其他线程调用notify或者notifyall才可以被唤醒(等待池)
2同步阻塞,运行的线程在获取对象的同步锁,如果该同步锁被其他线程占用,那么就会放锁池之中。
3其他阻塞
sleep jion()或者有i/o请求时,jvm会把线程设置为阻塞状态
新建new
就绪start
运行run
阻塞wait、io、sleep、wait
死亡stop
对线程安全的理解
不是线程安全,应该是内存安全,堆是共享内存,可以被所有线程访问
当多个线程访问同一个对象,不进行额外的同步控制之或者其他的协调操作是,调用这个对象可以获得正确得结果,则线程安全
堆是进程和线程共有的空间分为全局堆和局部堆,局部堆是用户分配的空间,全局堆就是所有没有被分配的空间,堆是操作系统进行初始化时分配的,运行状态也可以像系统要额外的堆,但是用完要还给操作系统,不然称之为内存泄漏。
栈是每一个线程独有,在初始化时,每个线程相互独立,栈是安全的,操作系统在切换线程会自动切换栈,占空间不需要显式的分配和释放。
因为堆是每一个线程都可以访问的所以这就是造成线程安全的潜在原因