示例1:匿名内置类
public class LazyDemo {
private static boolean initialized = false;
// LazyDemo static模块执行时(类还未完全初始化),Runnable 匿名内置类随之初始化
// 如果Runnable匿名内置类依赖了外部对象,就会导致类加载时出现循环等待,产生死锁
static {
print("static 模块执行!");
// Case 1 匿名内置类:(不能运行)
// 如果是匿名内内置类(LazyDemo$1.class)的话,它的类初始化依赖于外部类初始化
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// Runnable类依赖了LazyDemo类中的对象,产生了循环等待,导致死锁情况。
initialized = true;
}
});
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
print("main 执行!");
System.out.println(initialized);
}
private static void print(Object obj) {
System.out.printf("线程执行:[%s] - %s", Thread.currentThread().getName(), obj);
}
}
运行结果: 死锁不动了!
字节码指令:
示例2:lambdas表达式语法
public class LazyDemo {
private static boolean initialized = false;
static {
print("static 模块执行!");
// Case 2 lambdas表达式:invokedynamic指令实现(不能运行)
// lambdas语法是为了代替以前的匿名内部类,但是lambdas表达式实现方式和匿名内置类不一样,是用invokedynamic实现。
// LazyDemo static模块执行时(类还未完全初始化)lambdas表达式随之初始化
// 此lambdas语法会成为LazyDemo字节码指令的一部分,但该指令的完成又依赖于整个类的完成,就会导致类加载时出现循环等待,产生死锁
Thread t1 = new Thread(() -> {});
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
print("main 执行!");
System.out.println(initialized);
}
private static void print(Object obj) {
System.out.printf("线程执行:[%s] - %s", Thread.currentThread().getName(), obj);
}
}
运行结果: 死锁不动了!
字节码指令:
示例3:方法引用
public class LazyDemo {
private static boolean initialized = false;
static {
print("static 模块执行!");
// Case 3 方法引用:invokedynamic指令实现(能够运行)
// System.out::println:方法属于System.out对象类java.io.PrintStream,它被Bootstrap ClassLoader加载
// 早于LazyDemo.class的APP ClassLoader加载
Thread t1 = new Thread(
System.out::println
);
t1.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
print("main 执行!");
System.out.println(initialized);
}
private static void print(Object obj) {
System.out.printf("线程执行:[%s] - %s", Thread.currentThread().getName(), obj);
}
}
运行结果: 正常执行完了!
字节码指令:
感谢阅读,下次再见。ヾ( ̄▽ ̄)ByeBye!