volatile
定义
volatile变量规则:对volatile变量的写入操作必须在对该变量的读操作之前执行。
volatile变量规则只是一种标准,要求JVM实现保证volatile变量的偏序语义。结合程序顺序规则、传递性,该偏序语义通常表现为两个作用:
- 保持可见性
- 禁用重排序(读操作禁止重排序之后的操作,写操作禁止重排序之前的操作)
volatile变量规则:对volatile变量的写入操作必须在对该变量的读操作之前执行。
volatile变量规则只是一种标准,要求JVM实现保证volatile变量的偏序语义。结合程序顺序规则、传递性,该偏序语义通常表现为两个作用:
Exception in thread “main”: java.lang.OutOfMemoryError: Java heap space
原因:对象不能被分配到堆内存中。
Exception in thread “main”: java.lang.OutOfMemoryError: PermGen space
原因:类或者方法不能被加载到老年代。它可能出现在一个程序加载很多类的时候,比如引用了很多第三方的库。
JVM内存结构主要有三大块:·堆内存、方法区和栈·。
堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,
默认情况下年轻代按照8:1:1的比例来分配;
方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);
栈又分为java虚拟机栈和本地方法栈
主要用于方法的执行。
xx | xxxxxxxx | desc |
---|---|---|
堆(Heap) | 线程共享 | 所有的对象实例以及数组都要在堆上分配。 回收器主要管理的对象。 |
方法区(Method Area) | 线程共享 | Non-Heap(非堆) 存储类信息、常量、静态变量、即时编译器编译后的代码。 |
方法栈(JVM Stack) | 线程私有 | 存储局部变量表、操作栈、动态链接、方法出口,对象指针。 |
本地方法栈(Native Method Stack) | 线程私有 | 为虚拟机使用到的Native 方法服务。如Java使用c或者c++编写的接口服务时,代码在此区运行。 |
程序计数器(Program Counter Register) | 线程私有 | PC寄存器(PC Register) 当前线程所执行的字节码的行号指示器。指向下一条要执行的指令。 |
在通过一张图来了解如何通过参数来控制各区域的内存大小
1 | -Xms设置堆的最小空间大小 |
饱汉是变种最多的单例模式。我们从饱汉出发,通过其变种逐渐了解实现单例模式时需要关注的问题。
饱汉,即已经吃饱,不着急再吃,饿的时候再吃。所以他就先不初始化单例,等第一次使用的时候再初始化,即·“懒加载”·。
1 | // 饱汉 |
抽象类的队列式同步器
J.U.C是基于AQS实现的,AQS是一个同步器
,设计模式是模板模式
。
核心数据结构:双向链表 + state(锁状态)
底层操作:CAS
AQS核心思想是,如果被请求的共享资源空闲,那么就将当前请求资源的线程设置为有效的工作线程,将共享资源设置为锁定状态;如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中。
CLH:Craig、Landin and Hagersten队列,是单向链表,AQS中的队列是CLH变体的虚拟双向队列(FIFO),AQS是通过将每条请求共享资源的线程封装成一个节点来实现锁的分配。