@@ -7384,7 +7384,7 @@ ObjectInputStream ObjectOutputStream
73847384
73857385#### 字节流
73867386
7387- ##### 字节输入流
7387+ ##### 字节输入
73887388
73897389FileInputStream文件字节输入流:
73907390
@@ -7460,7 +7460,7 @@ System.out.println(rs);
74607460
74617461
74627462
7463- ##### 字节输出流
7463+ ##### 字节输出
74647464
74657465FileOutputStream文件字节输出流:
74667466
@@ -7552,9 +7552,9 @@ public class CopyDemo01 {
75527552
75537553#### 字符流
75547554
7555- ##### 字符输入流
7555+ ##### 字符输入
75567556
7557- FileReader: 文件字符输入流。
7557+ FileReader: 文件字符输入流
75587558
75597559 * 作用:以内存为基准,把磁盘文件的数据以字符的形式读入到内存,读取文本文件内容到内存中去。
75607560 * 构造器:
@@ -7606,9 +7606,9 @@ public class FileReaderDemo02 {//字符数组
76067606
76077607
76087608
7609- ##### 字符输出流
7609+ ##### 字符输出
76107610
7611- FileWriter文件字符输出流的使用。
7611+ FileWriter:文件字符输出流
76127612
76137613* 作用:以内存为基准,把内存中的数据按照字符的形式写出到磁盘文件中去
76147614* 构造器:
@@ -7941,6 +7941,10 @@ class User implements Serializable {
79417941
79427942
79437943
7944+ ****
7945+
7946+
7947+
79447948##### 反序列化
79457949
79467950对象反序列化(对象字节输入流):ObjectInputStream
@@ -12469,23 +12473,23 @@ public void localvarGC4() {
1246912473
1247012474安全点 (Safepoint):程序执行时并非在所有地方都能停顿下来开始GC,只有在安全点才能停下
1247112475
12472- - Safe Point的选择很重要 ,如果太少可能导致GC等待的时间太长,如果太多可能导致运行时的性能问题
12473- - 大部分指令的执行时间都非常短,通常会根据是否具有让程序长时间执行的特征为标准,选择些执行时间较长的指令作为Safe Point, 如方法调用、循环跳转和异常跳转等
12476+ - Safe Point 的选择很重要 ,如果太少可能导致GC等待的时间太长,如果太多可能导致运行时的性能问题
12477+ - 大部分指令的执行时间都非常短,通常会根据是否具有让程序长时间执行的特征为标准,选择些执行时间较长的指令作为 Safe Point, 如方法调用、循环跳转和异常跳转等
1247412478
1247512479在GC发生时,让所有线程都在最近的安全点停顿下来的方法:
1247612480
1247712481- 抢先式中断:没有虚拟机采用,首先中断所有线程,如果有线程不在安全点,就恢复线程让线程运行到安全点
1247812482- 主动式中断:设置一个中断标志,各个线程运行到各个 Safe Point 时就轮询这个标志,如果中断标志为真,则将自己进行中断挂起
1247912483
12480- 问题:Safepoint 保证程序执行时,在不太长的时间内就会遇到可进入GC的Safepoint ,但是当线程处于 Waiting 状态或Blocked状态 ,线程无法响应JVM的中断请求,运行到安全点去中断挂起,JVM也不可能等待线程被唤醒,对于这种情况,需要安全区域来解决
12484+ 问题:Safepoint 保证程序执行时,在不太长的时间内就会遇到可进入GC的 Safepoint ,但是当线程处于 Waiting 状态或 Blocked 状态 ,线程无法响应JVM的中断请求,运行到安全点去中断挂起,JVM也不可能等待线程被唤醒,对于这种情况,需要安全区域来解决
1248112485
1248212486安全区域 (Safe Region):指在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的
1248312487
1248412488运行流程:
1248512489
12486- - 当线程运行到Safe Region的代码时,首先标识已经进入了Safe Region,如果这段时间内发生GC,JVM会忽略标识为Safe Region状态的线程
12490+ - 当线程运行到 Safe Region 的代码时,首先标识已经进入了 Safe Region,如果这段时间内发生GC,JVM会忽略标识为 Safe Region 状态的线程
1248712491
12488- - 当线程即将离开Safe Region时 ,会检查JVM是否已经完成GC,如果完成了则继续运行,否则线程必须等待GC完成,收到可以安全离开SafeRegion的信号
12492+ - 当线程即将离开 Safe Region 时 ,会检查JVM是否已经完成GC,如果完成了则继续运行,否则线程必须等待GC 完成,收到可以安全离开 SafeRegion 的信号
1248912493
1249012494
1249112495
@@ -18638,174 +18642,6 @@ public class TestVolatile {
1863818642
1863918643
1864018644
18641- ***
18642-
18643-
18644-
18645- #### 单例模式
18646-
18647- ##### 饿汉式
18648-
18649- 单例模式有很多实现方法,饿汉、懒汉、静态内部类、枚举类,试分析每种实现下获取单例对象时的线程安全
18650-
18651- * 饿汉式:类加载就会导致该单实例对象被创建
18652-
18653- * 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
18654-
18655- ```java
18656- public final class Singleton implements Serializable {
18657- private Singleton() {}
18658- private static final Singleton INSTANCE = new Singleton();
18659- public static Singleton getInstance() {
18660- return INSTANCE;
18661- }
18662-
18663- //解决序列化问题
18664- protected Object readResolve() {
18665- return INSTANCE;
18666- }
18667- }
18668- ```
18669-
18670- * 问题1:为什么类加 final 修饰?
18671- 不被子类继承,防止子类中不适当的行为覆盖父类的方法,破坏了单例
18672-
18673- * 问题2:如果实现了序列化接口,怎么防止防止反序列化破坏单例?
18674-
18675- 将单例对象序列化再反序列化,对象从内存反序列化到程序中会重新创建一个对象,通过反序列化得到的对象是不同的对象,而且得到的对象不是通过构造器得到的,反序列化得到的对象不执行构造器
18676-
18677- 解决办法:
18678-
18679- * 对单例声明 transient,然后实现 readObject(ObjectInputStream in) 方法,复用原来的单例
18680-
18681- 条件:访问权限为private/protected、返回值必须是Object、异常可以不抛
18682- * 实现readResolve()方法,当 JVM 从内存中反序列化地"组装"一个新对象,就会自动调用readResolve方法返回原来单例
18683-
18684- * 问题3:为什么构造方法设置为私有? 是否能防止反射创建新的实例?
18685- 防止其他类无限创建对象;不能防止反射破坏
18686-
18687- * 问题4:这种方式是否能保证单例对象创建时的线程安全?
18688- 能,静态变量初始化在类加载时完成,由JVM保证线程安全
18689-
18690- * 问题5:为什么提供静态方法而不是直接将 INSTANCE 设置为 public?
18691- 更好的封装性、提供泛型支持、可以改进成懒汉单例设计
18692-
18693-
18694-
18695- ***
18696-
18697-
18698-
18699- ##### 枚举式
18700-
18701- ```java
18702- enum Singleton {
18703- INSTANCE;//相当于枚举类的静态成员变量
18704-
18705- public void doSomething() {
18706- System.out.println("doSomething");
18707- }
18708- }
18709- public static void main(String[] args) {
18710- Singleton.INSTANCE.doSomething();
18711- }
18712- ```
18713-
18714- * 问题1:枚举单例是如何限制实例个数的?每个枚举项都是一个实例,是一个静态成员变量
18715- * 问题2:枚举单例在创建时是否有并发问题?否
18716- * 问题3:枚举单例能否被反射破坏单例?否,反射创建对象时判断是枚举类型就直接抛出异常
18717- * 问题4:枚举单例能否被反序列化破坏单例?否
18718- * 问题5:枚举单例属于懒汉式还是饿汉式?**饿汉式**
18719- * 问题6:枚举单例如果希望加入一些单例创建时的初始化逻辑该如何做?添加构造方法
18720-
18721- 反编译后的:
18722-
18723- ```java
18724- public final class Singleton extends java.lang.Enum<Singleton> {//Enum实现序列化接口
18725- public static final Singleton INSTANCE = new Singleton();
18726- }
18727- ```
18728-
18729-
18730-
18731- ***
18732-
18733-
18734-
18735- ##### 懒汉式
18736-
18737- ```java
18738- public final class Singleton {
18739- private Singleton() { }
18740- private static Singleton INSTANCE = null;
18741- //分析这里的线程安全,并说明有什么缺点?锁范围太大,每次进入都要加锁
18742- public static synchronized Singleton getInstance() {
18743- if( INSTANCE != null ){
18744- return INSTANCE;
18745- }
18746- INSTANCE = new Singleton();
18747- return INSTANCE;
18748- }
18749- }
18750- ```
18751-
18752-
18753-
18754- ****
18755-
18756-
18757-
18758- ##### DCL
18759-
18760- ```java
18761- public final class Singleton {
18762- private Singleton() { }
18763- // 防止指令重排序
18764- private static volatile Singleton INSTANCE = null;
18765- // 首次使用getInstance()才加锁,后续使用时无需加锁,性能好
18766- public static Singleton getInstance() {
18767- if (INSTANCE != null) {
18768- return INSTANCE;
18769- }
18770- synchronized (Singleton.class) {
18771- // 防止首次创建Singleton时的并发的问题
18772- if (INSTANCE != null) { // t2
18773- return INSTANCE;
18774- }
18775- INSTANCE = new Singleton();
18776- return INSTANCE;
18777- }
18778- }
18779- }
18780- ```
18781-
18782-
18783-
18784- ***
18785-
18786-
18787-
18788- ##### 内部类
18789-
18790- ```java
18791- public final class Singleton {
18792- private Singleton() { }
18793-
18794- private static class LazyHolder {
18795- static final Singleton INSTANCE = new Singleton();
18796- }
18797-
18798- public static Singleton getInstance() {
18799- return LazyHolder.INSTANCE;
18800- }
18801- }
18802- ```
18803-
18804- * 问题1:属于懒汉式还是饿汉式?
18805- 懒汉式,类加载本身就是懒惰的,首次调用时加载,然后对单例进行初始化
18806- * 问题2:在创建时是否有线程安全问题?
18807- 没有,静态变量初始化在类加载时完成,由JVM保证线程安全
18808-
1880918645
1881018646
1881118647***
0 commit comments