一 点睛
对于 <clint>() 方法的调用,也就是类的初始化,虚拟机会在内部确保其多线程环境中的安全性。
虚拟机会保证一个类的<clint>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 <clint>() 方法,其他线程都需要阻塞等待,直到活动线程执行<clint>()方法完毕。
正是因为 <clint>() 带锁线程安全的},因此,如果在一个类<clint>() 方法中有耗时很长的操作,就可能造成多个线程阻塞,引发死锁。并且这种死锁是很难发现的,因为看起来它们并没有可用的锁信息。
如果之前的线程成功加载了类,则等在队列中的线程就没有机会再执行 <clint>() 方法了。那么,当需要使用这个类时,虚拟机会直接返回给它已经准备好的信息。
二 实战
1 代码
一 点睛
对于 <clint>() 方法的调用,也就是类的初始化,虚拟机会在内部确保其多线程环境中的安全性。
虚拟机会保证一个类的<clint>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 <clint>() 方法,其他线程都需要阻塞等待,直到活动线程执行<clint>()方法完毕。
正是因为 <clint>() 带锁线程安全的},因此,如果在一个类<clint>() 方法中有耗时很长的操作,就可能造成多个线程阻塞,引发死锁。并且这种死锁是很难发现的,因为看起来它们并没有可用的锁信息。
如果之前的线程成功加载了类,则等在队列中的线程就没有机会再执行 <clint>() 方法了。那么,当需要使用这个类时,虚拟机会直接返回给它已经准备好的信息。
二 实战
1 代码
package chapter03.java1;
/**
* 死锁举例
*/
class StaticA {
static {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
try {
Class.forName("chapter03.java1.StaticB");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("StaticA init OK");
}
}
class StaticB {
static {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
try {
Class.forName("chapter03.java1.StaticA");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("StaticB init OK");
}
}
public class StaticDeadLockMain extends Thread {
private char flag;
public StaticDeadLockMain(char flag) {
this.flag = flag;
this.setName("Thread" + flag);
}
@Override
public void run() {
try {
Class.forName("chapter03.java1.Static" + flag);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(getName() + " over");
}
public static void main(String[] args) throws InterruptedException {
StaticDeadLockMain loadA = new StaticDeadLockMain('A');
loadA.start();
StaticDeadLockMain loadB = new StaticDeadLockMain('B');
loadB.start();
}
}
2 测试
发生死锁
2 测试
发生死锁