高并发编程学习笔记(2)----类加载

JAVA ClassLoader

在上一篇中提到了两个方法
public ClassLoader getContextCLassLoader()获取线程上下文的类加载器
public void setContextClassLoader(ClassLoader cl)设置线程的类加载器
在上一篇中没有对线程上下文加载器相关方法做太多解析。要想说明白这个问题必须先掌握JVM的类加载原理和整个类的加载过程。所以这一篇更像是在讲JVM加载类的过程。

1.类的加载过程

每个类或者接口只有在首次主动使用时才会对其进行初始化。
在了解类的加载过程前需要知道什么是类的主动使用。
类的主动使用有以下六种场景:
1.通过new()关键字初始化类。
2.访问类的静态变量。
3.访问类的静态方法。
4.对某个类进行反射操作。
5.初始化子类会导致父类的初始化。
6.执行main函数所在类会导致该类的初始化。
除了上述六种情况,其余都被称为被动使用。不会导致类的加载和初始化。
下边举几个容易混淆的例子。
1.构造某个类的数组不会导致该类的初始化。

public static void main(String[] args)
{
	Circle[] c = new Circle[10];
	System.out.println(c.length);
}

上述new方法新建了一个Circle类型的数组,它并不能导致Circle类的初始化。该操作不过是在堆内存中开辟了一段连续的地址空间4byte*10。
2.引用类的静态常量不会导致类的初始化。

类的加载过程简介。

类的加载过程一般分为三个阶段:加载阶段、连接阶段、初始化阶段。连接阶段又可分为验证、准备、解析三个阶段。

1.加载阶段

类的加载就是将class文件中的二进制数据读到内存中,然后将该字节流所代表的静态存储结构转换为方法区中运行的数据结构,并且在堆内存中生成一个该类的java.lang.Class对象作为访问方法区数据结构的入口。
在这里插入图片描述
类加载的最终产物就是堆内存中的class对象。对于同一个ClassLoader来讲,不管某个类被加载了多少次,对应到堆内存区的class对象始终是同一个。

2.类的连接阶段

2.1验证

验证的主要目的是确保class文件的字节流所包含的内容符合JVM的规范要求,并且不会出现危害JVM自身安全的代码。其中包括
(1)验证文件格式包括魔术因子(class文件的魔术因子是0XCAFEBABE)、主次版本号(高版本JDK编译的低版本不能兼容)、常量池中是否在不支持的变量类型等。
(2)元数据的验证(确保class字节流符合JVM规范的要求)包括父类和接口是否存在且合法、是否继承被final修饰的类、是否为抽象类、是否实现父类所有抽象方法等。
(3)字节码验证:主要验证程序的控制流程。
(4)其他验证

2.2准备

当一个class的字节流通过类所有的验证过程后就要为类的静态变量分配内存并且设置初始值。静态变量会被分配到方法区中,不同于实例变量被分配到堆内存中。

2.3解析

解析就是在常量池中寻找类、接口、字段和方法的符号引用,并且将符号引用替换成直接引用的过程。

3.初始化

初始化阶段最主要的一件事情就是执行<clinit>()方法的过程。在<clinit>()方法中所有的类变量都会被赋予正确的值(在程序编写时指定的值)。<clinit>()方法包含了所有类的静态变量的赋值动作和静态语句块的执行代码。注意:静态语句块只能对后面的静态变量进行赋值,不能对其进行访问。
如果一个类中既没有静态代码块也没有静态变量,那么他就没有生成<clinit>()方法 的必要了。

2.JVM类加载器

顾名思义,类的加载器就是负责类的加载职责,对于任意的一个class,都需要由加载它的的类加载器和这个类本身确立其在JVM中的唯一性,也就是运行时包(后边会讲)。任何一个对象的class在JVM中只存在唯一的一份。但是不能绝对的理解为我们自定义的类在JVM中同样也是这样。
JVM为我们提供了三大内置的类加载器。不同的类加载器负责将不同的类加载到JVM中去,并且他们之间严格遵守着父委托的机制。

根类加载器

根类加载器又称为Booststrap类加载器,该加载器是最顶层的加载器。是由C++编写。主要负责虚拟机核心类库的加载,比如整个java.lang包都是由根加载器加载。
可以通过系统属性sun.boot.class.path来得知当前JVM的根加载器都加载了哪些资源

System.out.println(System.getProperty("sun.boot.class.path"));

扩展类加载器

扩展类加载器的父类是根加载器,是由纯JAVA语言实现的。它主要加载JAVA_HOME下的jre\lb\ext子目录里面的类库。可以通过系统属性java.ext.dirs获得扩展类加载器加载的资源。

系统类加载器

系统类加载器的父加载器是扩展类加载器,同时也是自定义类加载器的父加载器(默认)。它负责加载classpath下的类库资源。系统类加载器的加载路径一般通过“java.class.path”进行获取。

加载器工作原理(自己浅层次的理解)

首先将类的全名称转换为文件的全路径。在findClass方法中读取class文件的字节流数据。最后调用ClassLoader的defineClass方法对class完成定义。
类加载器的构造方法classLoader有两个属性String classDir、ClassLoader parent,分别表示class路径和父类加载器。
findClass原型为: protected Class<?> findClass(String name) throws ClassNotFountException。name为要加载类的全路径。
defineClass参数有(String name,byte[] b,int off,int len) name为定义类的名字,b 是文件的二进制字节数组,off是字节数组的偏移量,len是从偏移量开始读取的长度。(因为class字节数组不一定是从一个class文件中获得的,有可能是来自网络或者是编程的方式写入,一个字节数组可能有多个class字节信息所有需要偏移量)

双亲委托机制

双亲委托机制也称父委托机制。当一个类加载器被调用loadClass之后,他不会直接将其加载,而是先交给当前类加载器的父加载器尝试加载,直到最顶层的父加载器,然后在依次向下进行加载。
加载器加载一个类的过程:
1.从当前类加载器的已加载类缓存中根据类的全路径名查询是否存在该类,如果存在则直接返回(结束)。
2.如果当前类存在父类加载器,则调用父类加载器的loadClass方法对其加载。
3.如果当前加载器不存在父类加载器,则直接调用根类加载器对该类进行加载。
4.如果当前的所有父类加载器都没有成功加载class,则尝试调用当前类加载器的findClass方法对其进行加载,该方法也是我们自定义加载器需要重写的方法。

类加载器的命名空间

一般加载器进行类加载的时候,首先会到加载记录表(缓存)中,查看该类是否已经被加载过了,如果已经被加载过,就不会重复加载了。
每一个类加载器实例都有各自的命名空间,命名空间是由该加载器和其所有父类加载器所构成的,因此每个类加载器中同一个class都是独一无二的。
但是使用不同的类加载器,或者同一个类加载器的不同实例去加载同一个class则会在堆内存和方法区产生多个class对象。
所以更严谨的说法是同一个class实例在同一个类加载器命名空间之下是唯一的。

运行时包

我们在编写代码时通常会给一个类指定一个包名,包的作用是为了组织类,防止不同包下同样名称的class引起冲突,还能起到封装的作用,包名和类名构成了类的全限定名称。在JVM运行时class会有一个运行时包,运行时包是由类加载器的命名空间和类的全限定名称共同组成的。

初始类加载器

JVM规定了不同的运行时包下的类彼此之间是不可以进行访问的,那么为什么我们在开发的程序中(系统类加载器加载)可以访问java.lang(根加载器加载)包下的类呢?
这是因为每一个类在经过ClassLoader的加载后,在虚拟机中都会有对应的class实例,如果某个类C被类加载器CL加载,那么CL就被称为C的初始类加载器。JVM为每一个类加载维护了一个列表,该列表记录了将该类加载器作为初始类加载器的所有class,在加载一个类时,JVM使用这些列表;来判断该类是否被加载过了,是否需要首次加载。
根据JVM规范的规定,在类的加载过程中,所有参与的类加载器,即使没有亲自加载过该类,也都会被标识为该类的初始类加载器。再联想父委托机制,就知道为什么我们自定义的类可以访问java.lang包下的类了。

类的卸载

JVM规定了一个类只有在满足下面三个条件的时候才会被GC回收,也就是类被卸载。
1.该类的所有实例已经被GC。
2.加载该类的ClassLoader实例被回收。
3.该类的class实例没有在其他地方被引用。

3.线程上下文类加载器

还没搞懂,暂时不写。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
《Python学习笔记》是由皮大庆编写的一本关于Python语言学习的教材。在这本书中,作者详细介绍了Python语言的基础知识、语法规则以及常用的编程技巧。 首先,作者简要介绍了Python语言的特点和优势。他提到,Python是一种易于学习和使用的编程语言,受到了广大程序员的喜爱。Python具有简洁、清晰的语法结构,使得代码可读性极高,同时也提供了丰富的库和模块,能够快速实现各种功能。 接着,作者详细讲解了Python的基本语法。他从变量、数据类型、运算符等基础知识开始,逐步介绍了条件语句、循环控制、函数、模块等高级概念。同时,作者通过大量的示例代码和实践案例,帮助读者深对Python编程的理解和应用。 在书中,作者还特别强调了编写规范和良好的编程习惯。他从命名规范、注释风格、代码缩进等方面指导读者如何写出清晰、可读性强的Python代码。作者认为,良好的编程习惯对于提高代码质量和提高工作效率非常重要。 此外,作者还介绍了Python的常用库和模块。他提到了一些常用的库,如Numpy、Pandas、Matplotlib等。这些库在数据处理、科学计算、可视化等领域有广泛的应用,帮助读者更好地解决实际问题。 总的来说,《Python学习笔记》是一本非常实用和全面的Python学习教材。通过学习这本书,读者可以系统地学习和掌握Python编程的基础知识和高级应用技巧,为以后的编程学习和工作打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值