前言
程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的。
Java 8集合中的Stream相当于高级版的Iterator
Stream API通过Lambda表达式对集合进行各种非常便利高效的聚合操作,或者大批量数据操作
Stream的聚合操作与数据库SQL的聚合操作sorted、filter、map等非常类似
在数据操作方面,Stream不仅可以通过串行的方式实现数据操作,还可以通过并行的方式处理大批量数据,提高处理效率
Java集合的根接口是Collection,它又继承了迭代接口Iterable List接口和Set接口继承了Collection接口 Map接口是独立的接口,并没有继承Collection接口 (这里是重点,面试可能问的比较多) List接口常用的实现类有:ArrayList、LinkedList、Vector Set接口常用的实现类有:HashSet、LinkedHashSet、TreeSet Map接口常用的实现类有:HashMap、HashTable、TreeMap
内容
通常会将中间操作称为懒操作,正是因为懒操作结合终结操作,数据源构成的处理管道(Pipeline),实现了Stream的高效
JVM在判断两个class是否相同时,不仅要判断两个类名是否相同,还要判断是否是同一个类加载器加载的。
避免重复加载,父类已经加载了,则子CLassLoader没有必要再次加载。 考虑安全因素,假设自定义一个String类,除非改变JDK中CLassLoader的搜索类的默认算法,否则用户自定义的CLassLoader如法加载一个自己写的String类,因为String类在启动时就被引导类加载器Bootstrap CLassLoader加载了。
数组和集合都是Java中的容器 数组的长度是固定的,集合的长度是可变的 数组只能存储相同数据类型的数据,这里的数据类型可以是基本数据类型,也可以是引用类型 集合可以存储不同数据类型的对象的引用(但一般情况下,我们会使用泛型来约定只使用1种数据类型),但不能存储基本数据类型。
如果理解了,大家考虑这么一个问题:ReentrantLock(或者其它基于AQS实现的锁)是如何保证代码段中变量(变量主要是指共享变量,存在竞争问题的变量)的可见性?
Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量主要是指共享变量,存在竞争问题的变量。Java内存模型规定所有的变量都存储在主内存中,而每条线程还有自己的工作内存,线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量(根据Java虚拟机规范的规定,volatile变量依然有共享内存的拷贝,但是由于它特殊的操作顺序性规定——从工作内存中读写数据前,必须先将主内存中的数据同步到工作内存中,所有看起来如同直接在主内存中读写访问一般,因此这里的描述对于volatile也不例外)。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值得传递均需要通过主内存来完成。
小结
如果我们仔细分析concurrent包的源代码实现,会发现一个通用化的实现模式。
首先,声明共享变量为volatile。
然后,使用CAS的原子条件更新来实现线程之间的同步。
同时,配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。