澳门新葡萄京官网首页 17

澳门新葡萄京官网首页JVM原理分析

多线程

java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。

本地方法堆栈(Native Method Stacks)

Java所有的流类位于java.io包中,都分别继承字以下四种抽象流类型。

Type 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

澳门新葡萄京官网首页 1

继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。

继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。

TYPE:类、接口或enum声明

Sun Hotspot
JVM为了提升对象内存分配的效率,对于所有创建的线程都会分配一块独立的空间TLAB(Thread
Local Allocation
Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样的,但如果对象过大的话则仍然要直接使用堆空间分配。

类加载

变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

Execution Engine:用于执行字节码或者本地方法。

目前在搞 Node.js,曾经的 JAVA
知识忘了好多,为此整理了下,感叹下工业语言还是有相当的优势的。

@Inherited

JVM(Java Virtual Machine,
Java虚拟机)
是JRE的一部分。JVM主要工作是解释自己的指令集并映射到本地的CPU指令集和OS的系统调用。Java语言是跨平台运行的,不同的操作系统会有不同的JVM映射规则,使之与操作系统无关,完成跨平台性。

线程池

concurrent下的线程池:

名称 功能
ExecutorService 真正的线程池接口
ScheduledExecutorService 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题
ThreadPoolExecutor ExecutorService的默认实现
ScheduledThreadPoolExecutor 继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现

Executors

newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

Permanent Generation (图中的Permanent
Space)存放JVM自己的反射对象,比如类对象和方法对象

不允许卸载类:类加载器可以加载一个类,但不能够卸载一个类。但是类加载器可以被创建或者删除。

关键字

strictfp(strict float point)

strictfp
关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是
IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。

如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。

transiant

变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

Volatile

作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。

final

  1. 修饰基础数据成员(as const)
  2. 修饰类或对象的引用
  3. 修饰方法的final(cannot overwrite)
  4. 修饰类或者参数

修饰方法的final(cannot overwrite)

2.Extension ClassLoader

注解

Java SE5内置了三种标准注解:

 @Override,表示当前的方法定义将覆盖超类中的方法。

 @Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。

 @SuppressWarnings,关闭不当编译器警告信息。

Java还提供了4中注解,专门负责新注解的创建:

@Target:

表示该注解可以用于什么地方,可能的ElementType参数有:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明

@Retention

表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息

@Document

将注解包含在Javadoc中

@Inherited

允许子类继承父类中的注解

Example

定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
    public String id();
    public String description() default "no description";
}

使用注解:

public class PasswordUtils {
     @UseCase(id = 47, description = "Passwords must contain at least one numeric")
     public boolean validatePassword(String password) {
         return (password.matches("\w*\d\w*"));
     }

     @UseCase(id = 48)
     public String encryptPassword(String password) {
         return new StringBuilder(password).reverse().toString();
     }
 }

解析注解:

public static void main(String[] args) {
     List<Integer> useCases = new ArrayList<Integer>();
     Collections.addAll(useCases, 47, 48, 49, 50);
     trackUseCases(useCases, PasswordUtils.class);
 }

 public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
     for (Method m : cl.getDeclaredMethods()) {
         UseCase uc = m.getAnnotation(UseCase.class);
         if (uc != null) {
             System.out.println("Found Use Case:" + uc.id() + " "
                         + uc.description());
             useCases.remove(new Integer(uc.id()));
         }
     }
     for (int i : useCases) {
         System.out.println("Warning: Missing use case-" + i);
     }
 }
 // Found Use Case:47 Passwords must contain at least one numeric
 // Found Use Case:48 no description
 // Warning: Missing use case-49
 // Warning: Missing use case-50

@Target:

子类调用了初始化

初始化

父静态->子静态
父变量->父初始化区->父构造
子变量->子初始化区->子构造

定义注解:

澳门新葡萄京官网首页 2

内存模型

澳门新葡萄京官网首页 3

Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的
工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,首先是定义了8种原子操作:

  • lock:将主内存中的变量锁定,为一个线程所独占
  • unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量
  • read:将主内存中的变量值读到工作内存当中
  • load:将read读取的值保存到工作内存中的变量副本中。
  • use:将值传递给线程的代码执行引擎
  • assign:将执行引擎处理返回的值重新赋值给变量副本
  • store:将变量副本的值存储到主内存中。
  • write:将store存储的值写入到主内存的共享变量当中。

异常

对旧生代的对象收集称为Full GC

异常

澳门新葡萄京官网首页 4

Java的异常(包括Exception和Error)分为:

可查的异常(checked exceptions)

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

不可查的异常(unchecked exceptions)

包括运行时异常(RuntimeException与其子类)和错误(Error)。

运行时异常和非运行时异常:

RuntimeException

NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

RuntimeException以外的Exception

从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

初始化

完成校验后,JVM初始化类中的静态变量,并将其赋值为默认值。

加载器

BootStrap ClassLoader

启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。

   URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
   for (int i = 0; i < urls.length; i++) {
       System.out.println(urls[i].toExternalForm());  
   }
   // 也可以通过sun.boot.class.path获取
   System.out.println(System.getProperty("sun.boot.class.path"))

Extension ClassLoader

扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。

App ClassLoader

系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

注意:

除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内。Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。

澳门新葡萄京官网首页 5

层级结构

安全性

  1. 严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。
  2. 无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。
  3. 数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。
  4. 强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException
  5. 语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。
  6. 垃圾回收。
  7. Exception。

修饰基础数据成员

最后对比类中的所有属性、方法进行验证,以确保要调用的属性、方法存在,以及具备访问权限(例如private、public等),否则会造成NoSuchMethodError、NoSuchFieldError等错误信息。

原理

ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap
ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap
ClassLoader试图加载,如果没加载到,则把任务转交给Extension
ClassLoader试图加载,如果也没加载到,则转交给App
ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。

多线程

主要的执行计数:

内存组成

堆(Heap)

运行时数据区域,所有类实例和数组的内存均从此处分配。Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器
的自动内存管理系统回收。

  • News Generation(Young Generation即图中的Eden + From Space + To
    Space)

    • Eden 存放新生的对象
    • Survivor Space 两个 存放每次垃圾回收后存活的对象
  • Old Generation(Tenured Generation 即图中的Old Space)
    主要存放应用程序中生命周期长的存活对象

非堆内存

JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。

  • Permanent Generation  (图中的Permanent
    Space)存放JVM自己的反射对象,比如类对象和方法对象
  • native heap

transiant

跟ClassLoader,C++实现,JVM启动时初始化此ClassLoader,并由此完成$JAVA_HONE中jre/lib/rt.jar(Sun
JDK的实现)中所有class文件的加载,这个jar中包含了java规范定义的所有接口以及实现。

目录

  • 异常
  • 注解
  • 安全性
  • 类加载
  • 关键字
  • 初始化
  • 多线程
  • 线程池
  • 内存模型

实例方法

委派模式(Delegation Mode)

包括运行时异常(RuntimeException与其子类)和错误。

方法区域存放所加载类的信息、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName,isInstance等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,就会抛出OutOfMemory的错误信息。

运行时数据区域,所有类实例和数组的内存均从此处分配。Java虚拟机启动时创建。对象的堆内存由称为垃圾回收器
的自动内存管理系统回收。

JVM用此ClassLoader来加载启动参数中指定的ClassPath中的jar包以及目录,在Sun
JDK中ClassLoader对应的类名为AppClassLoader。

read:将主内存中的变量值读到工作内存当中

在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代。

不可查的异常(unchecked exceptions)

运行时数据区:方法区、堆、java栈、pc寄存器、本地方法栈。

RuntimeException

虚引用:虚引用只是用来得知对象是否被GC。

加载器

强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用时,
GC时才会被回收)

运行时异常和非运行时异常:

软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有内存不够的情况下才会被GC)

RuntimeException以外的Exception

在执行方法时JVM提供了四种指令来执行

调用 new

如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp。

1.装载:负责找到二进制字节码并加载至JVM中,JVM通过类名、类所在的包名、ClassLoader完成类的加载。因此,标识一个被加载了的类:类名

Java所有的流类位于

JVM栈

有四个线程1、2、3、4。线程1的功能就是输出1,线程2的功能就是输出2,以此类推………现在有四个文件ABCD。初始都为空。现要让四个文件呈如下格式:A:1
2 3 4 1 2…. B:2 3 4 1 2 3…. C:3 4 1 2 3 4…. D:4 1 2 3 4 1….

它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。

newCachedThreadPool

1.启动。启动一个Java程序,一个JVM实例就产生。拥有public static void
main(String[] args)函数的class可以作为JVM实例运行的起点。

load:将read读取的值保存到工作内存中的变量副本中。

invokespecial:JVM对于初始化对象(Java构造器的方法为:)以及调用对象实例的私有方法时。

实例方法中的同步块

Java加载类的过程:

垃圾回收。

invokeinterface:将属性定义为接口来进行调用。

系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件

所有新创建的Object都将会存储在新生代Young Generation中。如果Young
Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。新的Object总是创建在Eden
Space。

表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:

2.链接:负责对二进制字节码的格式进行校验、初始化装载类中的静态变量以及解析类中调用的接口。

父静态->子静态

弱引用:在GC时一定会被GC回收。

子变量->子初始化区->子构造

自适应优化(目前sun的HotspotJVM采用这种技术),吸取第一代JVM和第二代JVM的经验,采用两者结合的方式,开始对所有的代码都采用解释执行的方式,并监视代码执行情况,然后对那些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行优化。若方法不再频繁使用,则取消编译过代码,仍对其进行解释执行。

URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); for
(int i = 0; i < urls.length; i++) {
System.out.println(urls[i].toExternalForm; } //
也可以通过sun.boot.class.path获取
System.out.println(System.getProperty(“sun.boot.class.path”))

澳门新葡萄京官网首页 6

修饰类或者参数

类加载器将字节码载入内存后,执行引擎以java字节码为单元,读取java字节码。java字节码机器读不懂,必须将字节码转化为平台相关的机器码。这个过程就是由执行引擎完成的。

ThreadLocal

3.初始化(initializing):负责执行类中的静态初始化代码、构造器代码以及静态属性的初始化,以下四种情况初始化过程会被触发。

注:加群要求 学习交流群:642830685

堆在JVM启动的时候就被创建,堆中储存了各种对象,这些对象被自动管理内存系统(Automatic
Storage Management System),也就是常说的“Garbage
Collector”管理。这些对象无需、也无法显示地被销毁。

Atomic 包在 Atomic 包里一共有 12
个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。某些并发问题,需要无锁解决时,就可以考虑使用原子方法。

方法区域(Method Area)

public class PasswordUtils { @UseCase(id = 47, description = “Passwords
must contain at least one numeric”) public boolean
validatePassword(String password) { return
(password.matches(“\w*\d\w*”)); } @UseCase public String
encryptPassword(String password) { return new
StringBuilder.reverse().toString(); } }

可见性限制:下层的加载器能够看到上层加载器中的类,反之则不行,委派只能从下到上

Old Generation(Tenured Generation 即图中的Old Space)
主要存放应用程序中生命周期长的存活对象

GC的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。

无指针运算。java中的操作,除了基本类型都是引用的操作。引用是不能进行增减运算,不能被直接赋予内存地址的,从而增加了内存级的安全性。

程序中主动调用System.gc()强制执行的GC为Full GC。

PARAMETER:参数声明

澳门新葡萄京官网首页 7

解析注解:

User-Defined
ClassLoader是Java开发人员继承ClassLoader抽象类实现的ClassLoader,基于自定义的ClassLoader可用于加载非ClassPath中的jar以及目录。

@Document

JVM用此classloader来加载扩展功能的一些jar包

内存模型

对新生代的对象收集称为minor GC

Java还提供了4中注解,专门负责新注解的创建:

1.Booststrap ClassLoader

strictfp
关键字可应用于类、接口或方法。使用strictfp关键字声明一个方法时,该方法中所有的float和double表达式都严格遵守FP-strict的限制,符合IEEE-754规范。当对一个类或接口使用strictfp关键字时,该类中的所有代码,包括嵌套类型中的初始设定值和代码,都将严格地进行计算。严格约束意味着所有表达式的结果都必须是
IEEE 754算法对操作数预期的结果,以单精度和双精度格式表示。

运行时常量池(Runtime Constant Pool)

原理

public static void main(String[] args) { List useCases = new
ArrayList(); Collections.addAll(useCases, 47, 48, 49, 50);
trackUseCases(useCases, PasswordUtils.class); } public static void
trackUseCases(List useCases, Class cl) { for (Method m :
cl.getDeclaredMethods { UseCase uc = m.getAnnotation(UseCase.class); if
(uc != null) { System.out.println(“Found Use Case:” + uc.id() + ” ” +
uc.description; useCases.remove(new Integer; } } for (int i : useCases)
{ System.out.println(“Warning: Missing use case-” + i); } } // Found Use
Case:47 Passwords must contain at least one numeric // Found Use Case:48
no description // Warning: Missing use case-49 // Warning: Missing use
case-50

堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,导致new对象的开销比较大。

newFixedThreadPool

澳门新葡萄京官网首页 8

JVM具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在Java虚拟机启动时创建的。除了方法区外,Java虚拟机实现可能需要用于内部处理或优化的内存,这种内存也是非堆内存。例如,JIT编译器需要内存来存储从Java虚拟机代码转换而来的本机代码,从而获得高性能。

invokevirtual:调用对象实例的方法。

native heap

澳门新葡萄京官网首页 9

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

总结:使用JDK(调用JAVA
API)开发JAVA程序后,通过JDK中的编译程序将Java程序编译为Java字节码,在JRE上运行这些字节码,JVM会解析并映射到真实操作系统的CPU指令集和OS的系统调用。

ReentrantLock / Condition

JVM启动过程终止定的初始化类

store:将变量副本的值存储到主内存中。

用于存储每个线程下一步将要执行的JVM指令,若该方法为native的,则PC寄存器中不存储任何信息。Java多线程情况下,每个线程都有一个自己的PC,以便完成不同线程上下文环境的切换。

newScheduledThreadPool

JVM执行引擎实例则对应了属于用户运行程序线程它是线程级别的。

注解

  • 包名 + ClassLoader实例ID。

SOURCE:注解将被编译器丢弃

3.System ClassLoader

并发容器

JVM是Java Virtual
Machine的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码,就可在多种平台上不加修改的运行,这也是Java能够“一次编译,到处运行的”原因。

静态方法中的同步块

解释,即时执行,自适应优化、芯片级直接执行。

LOCAL_VARIABLE:局部变量声明

TLAB仅作用于新生代的Eden
Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。

作为指令关键字,确保本条指令不会因编译器的优化而省略,修饰变量,保证变量每次都是从内存中重新读取。

当JVM加载一个类的时候,下层的加载器会将任务给上一层类加载器,上一层加载检查它的命名空间中是否已经加载这个类,如果已经加载,直接使用这个类。如果没有加载,继续往上委托直到顶部。检查之后,按照相反的顺序进行加载。如果Bootstrap加载器不到这个类,则往下委托,直到找到这个类。一个类可以被不同的类加载器加载。

线程安全是一个很大的问题,Java 最常见的 HttpServlet
就是单实例多线程,解决这样的问题,有多种方式:

存放的为类中的固定常量信息、方法和Field的引用信息等,其空间从方法区域中分配。

CONSTRUCTOR:构造器的声明

反射调用了类中的方法

严格遵循面向对象的规范。这样封装了数据细节,只提供接口给用户。增加了数据级的安全性。

PC寄存器

当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap
ClassLoader试图加载,如果没加载到,则把任务转交给Extension
ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader
进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。

不同的对象引用类型,GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型

允许子类继承父类中的注解

JDK(Java Development
Kit,Java开发工具包)
是用来编译、调试Java程序的开发工具包。包括Java工具(javac/java/jdb等)和Java基础的类库(java
API )。

类加载

解释属于第一代JVM

ThreadLocal
看下一节的内存图就很好理解,每个线程都有自己的工作内存,ThreadLocal
就是将变量存到线程自己的工作内存中,所以不会有并发问题。

3.消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。

newSingleThreadExecutorExecutors

即时编译JIT属于第二代JVM

将注解包含在Javadoc中

下图表示了JDK、JRE和JVM三者间的关系:

PACKAGE:包声明

Java实例对应一个独立运行的Java程序(进程级别

Exception。

澳门新葡萄京官网首页 10

如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

JVM将Heap分为两块:新生代New Generation和旧生代Old Generation

可查的异常(checked exceptions)

澳门新葡萄京官网首页 11

News Generation(Young Generation即图中的Eden + From Space + To Space)

澳门新葡萄京官网首页 12

CLASS:注解在class文件中可用,但会被VM丢弃

JVM采用本地方法堆来支持native方法的执行,此区域用于存储每个native方法调用的状态。

write:将store存储的值写入到主内存的共享变量当中。

2.运行。main()作为程序初始线程的起点,任何其他线程均可由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM使用,程序可以指定创建的线程为守护线程。

Survivor Space 两个 存放每次垃圾回收后存活的对象

Class Loader:用于装载.class文件。

继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit)。

JRE(Java Runtime Environment,
Java运行环境)
是Java平台,所有的程序都要在JRE下才能够运行。包括JVM和Java核心类库和支持文件。

继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit)。

4.User-Defined ClassLoader

Example

JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放当前线程中局部基本类型的变量(Java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack
Frame,非基本类型的对象在JVM栈上仅存放一个指向堆的地址。

非堆内存

invokestatic:调用类的static方法。

注意

final

Java SE5内置了三种标准注解:

澳门新葡萄京官网首页 13澳门新葡萄京官网首页 14

assign:将执行引擎处理返回的值重新赋值给变量副本

@Retention

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

volatile

常见的 ConcurrentHashMap CopyOnWriteArrayList
用于多线程下存放数据,Queue BlockingQueue 用于排队消费。

线程池

Synchronized

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

App ClassLoader

METHOD:方法声明

父变量->父初始化区->父构造

从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

BootStrap ClassLoader

use:将值传递给线程的代码执行引擎

synchronized
不够灵活,例如读写文件,读和读之间不应该互斥,这个时候就可以使用
ReentrantLock 增加并发能力。Condition 是绑定到 Lock
上的,可以用于线程间通信,例如这个面试题,就可以使用 Condition
唤起线程写自己的name 。

语言对线程安全的支持。java从语言级支持线程。从而从语法和语言本身做了很多对线程的控制和支持。

使用注解:

unclock:将lock加的锁定解除,此时其它的线程可以有机会访问此变量

concurrent下的线程池

澳门新葡萄京官网首页 15

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

lock:将主内存中的变量锁定,为一个线程所独占

扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。

Eden 存放新生的对象

synchronized锁住的是括号里的对象,而不是代码。对于非 static 的
synchronized 方法,锁的就是对象本身也就是 this。该关键字可以加到:

安全性

如何保证多个线程操作主内存的数据完整性是一个难题,Java内存模型也规定了工作内存与主内存之间交互的协议,首先是定义了8种原子操作:

启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public
@interface UseCase { public String id(); public String description()
default “no description”;}

关键字

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

Java的异常(包括ExceptionError)分为:

数组边界检查。这样就不会出现C/C++中的缓存溢出等安全漏洞。

强制类型转换。非同类型的对象之间不能进行转换,否则会抛出ClassCastException

表示该注解可以用于什么地方,可能的ElementType参数有:

修饰类或对象的引用

Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的
工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap
ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。

除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension
ClassLoader和App ClassLoader)在内。Bootstrap
ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap
ClassLoader也随着启动,负责加载完核心类库后,并构造Extension
ClassLoader和App ClassLoader类加载器。

线程安全

澳门新葡萄京官网首页 16

Extension ClassLoader

澳门新葡萄京官网首页 17

RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统能够创建的最大线程大小。

内存组成

FIELD:域声明

1、想学习JAVA这一门技术, 对JAVA感兴趣零基础,想从事JAVA工作的。

2、工作1-5年,感觉自己技术不行,想提升的

3、如果没有工作经验,但基础非常扎实,想提升自己技术的。

4、还有就是想一起交流学习的。

5.小号加群一律不给过,谢谢。

转发此文章请带上原文链接,否则将追究法律责任

strictfp(strict float point)

@Override,表示当前的方法定义将覆盖超类中的方法。
@Deprecated,使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。
@SuppressWarnings,关闭不当编译器警告信息。

NullPointerException、IndexOutOfBoundsException等这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

静态方法

发表评论

电子邮件地址不会被公开。 必填项已用*标注