@@ -2927,14 +2927,13 @@ public class Demo {
29272927 public static void main(String[] args) {
29282928 String s1 = "a"; // 懒惰的
29292929 String s2 = "b";
2930- String s3 = "ab";
2930+ String s3 = "ab";//串池
29312931 // new StringBuilder().append("a").append("b").toString() new String("ab")
2932- String s4 = s1 + s2;
2932+ String s4 = s1 + s2; //d
29332933 String s5 = "a" + "b"; // javac 在编译期间的优化,结果已经在编译期确定为ab
29342934
29352935 System.out.println(s3 == s4); // false
29362936 System.out.println(s3 == s5); // true
2937- System.out.println(s3 == s6); // true
29382937
29392938 String x2 = new String("c") + new String("d"); // new String("cd")
29402939 // 虽然new,但是在字符串常量池没有 cd 对象,toString()方法
@@ -13436,13 +13435,13 @@ JVM是通过栈帧中的对象引用访问到其内部的对象实例:(内
1343613435
1343713436在Java中,对象的生命周期包括以下几个阶段:
1343813437
13439- 1. 创建阶段(Created):
13440- 2. 应用阶段(In Use):对象至少被一个强引用持有着
13441- 3. 不可见阶段(Invisible):程序的执行已经超出了该对象的作用域,不再持有该对象的任何强引用
13442- 4. 不可达阶段(Unreachable):该对象不再被任何强引用所持有,包括GC Root的强引用
13443- 5. 收集阶段(Collected):垃圾回收器已经对该对象的内存空间重新分配做好准备,该对象如果重写了finalize()方法,则会去执行该方法
13444- 6. 终结阶段(Finalized):等待垃圾回收器对该对象空间进行回收,当对象执行完finalize()方法后仍然处于不可达状态时进入该阶段
13445- 7. 对象空间重分配阶段(De-allocated):垃圾回收器对该对象的所占用的内存空间进行回收或者再分配
13438+ 1. 创建阶段 (Created):
13439+ 2. 应用阶段 (In Use):对象至少被一个强引用持有着
13440+ 3. 不可见阶段 (Invisible):程序的执行已经超出了该对象的作用域,不再持有该对象的任何强引用
13441+ 4. 不可达阶段 (Unreachable):该对象不再被任何强引用所持有,包括GC Root的强引用
13442+ 5. 收集阶段 (Collected):垃圾回收器已经对该对象的内存空间重新分配做好准备,该对象如果重写了finalize()方法,则会去执行该方法
13443+ 6. 终结阶段 (Finalized):等待垃圾回收器对该对象空间进行回收,当对象执行完finalize()方法后仍然处于不可达状态时进入该阶段
13444+ 7. 对象空间重分配阶段 (De-allocated):垃圾回收器对该对象的所占用的内存空间进行回收或者再分配
1344613445
1344713446
1344813447
@@ -13583,7 +13582,7 @@ Java对象创建时机:
1358313582
1358413583 * 实例初始化不一定要在类初始化结束之后才开始
1358513584
13586- * 在同一个类加载器下,一个类型只会被初始化一次。所以一旦开始初始化一个类,无论是否完成后续都不会再重新触发该类型的初始化阶段了( 只考虑在同一个类加载器下的情形) 。因此,在实例化上述程序中的st变量时,**实际上是把实例初始化嵌入到了静态初始化流程中,并且在上面的程序中,嵌入到了静态初始化的起始位置**,这就导致了实例初始化完全发生在静态初始化之前,这也是导致a为110 b为0的原因
13585+ * 在同一个类加载器下,一个类型只会被初始化一次。所以一旦开始初始化一个类,无论是否完成后续都不会再重新触发该类型的初始化阶段了( 只考虑在同一个类加载器下的情形。因此,在实例化上述程序中的st变量时,**实际上是把实例初始化嵌入到了静态初始化流程中,并且在上面的程序中,嵌入到了静态初始化的起始位置**,这就导致了实例初始化完全发生在静态初始化之前,这也是导致a为110 b为0的原因
1358713586
1358813587 代码等价于:
1358913588
@@ -13777,6 +13776,10 @@ class D {
1377713776
1377813777
1377913778
13779+ ***
13780+
13781+
13782+
1378013783##### clinit
1378113784
1378213785<clinit>():类构造器,由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的
@@ -13786,7 +13789,7 @@ class D {
1378613789* 如果类中没有静态变量或静态代码块,那么clinit方法将不会被生成
1378713790* 在执行clinit方法时,必须先执行父类的clinit方法
1378813791* clinit方法只执行一次
13789- * static变量的赋值操作和静态代码块的合并顺序由源文件中出现的顺序决定
13792+ * static变量的赋值操作和静态代码块的合并顺序由源文件中**出现的顺序**决定
1379013793
1379113794**线程安全**问题:
1379213795
@@ -13798,7 +13801,7 @@ class D {
1379813801```java
1379913802public class Test {
1380013803 static {
13801- i = 0; // 给变量赋值可以正常编译通过
13804+ // i = 0; // 给变量赋值可以正常编译通过
1380213805 System.out.print(i); // 这句编译器会提示“非法向前引用”
1380313806 }
1380413807 static int i = 1;
@@ -13811,6 +13814,10 @@ public class Test {
1381113814
1381213815
1381313816
13817+ ****
13818+
13819+
13820+
1381413821##### 时机
1381513822
1381613823类的初始化是懒惰的,初始化时机:
@@ -13836,6 +13843,10 @@ public class Test {
1383613843
1383713844
1383813845
13846+ ***
13847+
13848+
13849+
1383913850##### init
1384013851
1384113852init指的是实例构造器,主要作用是在类实例化过程中执行,执行内容包括成员变量初始化和代码块的执行
@@ -17464,11 +17475,10 @@ public static void main(String[] args) {
1746417475
1746517476对比wait & notify:
1746617477
17467- * wait,notify 和 notifyAll 必须配合Object Monitor一起使用 ,而park、unpark不需要
17478+ * wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用 ,而park、unpark不需要
1746817479* park & unpark以线程为单位来阻塞和唤醒线程,而notify 只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程
17469- * **park & unpark 可以先 unpark**,而 wait & notify 不能先 notify
17470- 类比生产消费,先消费发现有产品就消费,没有就等待;先生产就直接产生商品,然后线程直接消费
17471- * wait会释放锁资源进入等待队列,park 不会释放锁资源,只负责阻塞当前线程,会释放CPU
17480+ * **park & unpark 可以先 unpark**,而 wait & notify 不能先 notify。类比生产消费,先消费发现有产品就消费,没有就等待;先生产就直接产生商品,然后线程直接消费
17481+ * wait 会释放锁资源进入等待队列,park 不会释放锁资源,只负责阻塞当前线程,会释放CPU
1747217482
1747317483原理:
1747417484
@@ -17711,17 +17721,23 @@ class GuardedObject {
1771117721```java
1771217722public static void main(String[] args) throws InterruptedException {
1771317723 Thread t1 = new Thread(() -> {
17714- try { Thread.sleep(1000); } catch (InterruptedException e) { }
17715- // 当没有『许可』时,当前线程暂停运行;有『许可』时,用掉这个『许可』,当前线程恢复运行
17716- LockSupport.park();
17717- System.out.println("1");
17718- }).start();
17719-
17720- Thread t2 = new Thread(() -> {
17721- System.out.println("2");
17722- // 给线程 t1 发放『许可』(多次连续调用 unpark 只会发放一个『许可』)
17723- LockSupport.unpark(t1);
17724- }).start();
17724+ while (true) {
17725+ //try { Thread.sleep(1000); } catch (InterruptedException e) { }
17726+ // 当没有许可时,当前线程暂停运行;有许可时,用掉这个许可,当前线程恢复运行
17727+ LockSupport.park();
17728+ System.out.println("1");
17729+ }
17730+ });
17731+ Thread t2 = new Thread(() -> {
17732+ while (true) {
17733+ System.out.println("2");
17734+ // 给线程 t1 发放『许可』(多次连续调用 unpark 只会发放一个『许可』)
17735+ LockSupport.unpark(t1);
17736+ try { Thread.sleep(500); } catch (InterruptedException e) { }
17737+ }
17738+ });
17739+ t1.start();
17740+ t2.start();
1772517741}
1772617742```
1772717743
0 commit comments