静态块确实是在main之前运行,但这不是关键。 关键在于类的初始化过程。
类的初始化,包括静态赋值如 static boolean initialized = false和静态初始化块, static { ... }, 按照声明的顺序依次执行。某个线程在对某个类进行初始化的时候,会先给这个类加锁,直到初始化全部完成之后才释放锁。 你的代码存在死锁问题。
把代码改成这样,看看输出是什么:
public class HelloWorld {
private static boolean initialized = false
static Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("aaaa")
System.out.println(initialized)// label
System.out.println("Hello ")
initialized = true
}
})
static {
t.start()
}
static {
try {
Thread.sleep(500)
}
catch(Exception e) {
}
System.out.println("bbbb")
}
public static void main(String[] args) {
System.out.println(" world!")
}
}
你会发现输出是这样的:
aaaa
bbbb
false ....
注意,bbbb总是在false之前打印,不管sleep多长时间。
而在run方法里,打印aaaa之后应该紧接着打印false才对,为什么还要等待睡觉中的bbbb呢?
虚拟机在执行 main之前,先要加载HelloWorld类,那么mian线程会对HelloWorld的Class加锁,然后依次执行
static boolean initialized = false
static Thread t = ...
static { t.start()}
static { sleep(500)print "bbbb"}
执行完这些语句,才会把锁释放。
在这之间,启动了t线程,t先打印aaaa,然后试图打印initialized,但是这时候HelloWorld的Class被锁定了,所以t线程必须等待main线程把锁释放掉,也就是上面所有的static语句执行完毕。等main线程执行完了bbbb,就会把锁释放掉,然后t线程就可以继续执行了。
如果加入了join语句,那么main线程就会等待t线程,但是t线程试图访问initialized的时候必须等待main线程,这就导致了死锁。你把label语句去掉之后,就不需要等到main线程了,所以会把hello打印出来。
总的结论:java是线程安全的,即对任何方法(包括静态方法)都可以不考虑线程冲突,但有一个前提,就是不能存在全局变量。如果存在全局变量,则需要使用同步机制。\x0d\x0a\x0d\x0a如下通过一组对比例子从头讲解:\x0d\x0a 在多线程中使用静态方法会发生什么事?也就是说多线程访问同一个类的static静态方法会发生什么事?是否会发生线程安全问题?\x0d\x0apublic class Test {\x0d\x0apublic static void operation(){\x0d\x0a// ... do something\x0d\x0a}\x0d\x0a}\x0d\x0a 事实证明只要在静态函数中没有处理多线程共享数据,就不存在着多线程访问同一个静态方法会出现资源冲突的问题。下面看一个例子:\x0d\x0apublic class StaticThread implements Runnable {\x0d\x0a@Override\x0d\x0apublic void run() {\x0d\x0a// TODO Auto-generated method stub\x0d\x0aStaticAction.print()\x0d\x0a}\x0d\x0apublic static void main(String[] args) {\x0d\x0afor (int i = 0i 回答于 2022-12-11