我有一个意想不到的(至少对我来说)输出这段代码
public class Test {
static boolean condition = false;
void runme() {
var reader = new Runnable() {
@Override
public void run() {
synchronized (this) {
System.out.println("waiting for condition");
while (!condition) {}
System.out.println("condition is true");
}
}
};
var writer = new Runnable() {
@Override
public void run() {
synchronized (this) {
System.out.println("condition is set to true");
condition = true;
}
}
};
new Thread(reader).start();
new Thread(writer).start();
}
public static void main(String[] args) {
new Test().runme();
}
}
根据文档,如果 reader
对象先启动,我预计会出现死锁,因为
- 它获取
this
的锁(进入同步块(synchronized block)) - 打印“等待条件”
- 永远陷入死循环
- 另一个线程等待
这个
锁,进入它自己的同步块(synchronized block)
但是,在某些代码运行中我得到了输出
waiting for condition
condition is set to true
condition is true
我是否遗漏了什么或者我是否误解了同步块(synchronized block)/方法的工作原理?
最佳答案
两个synchronized (this)
语句引用了Runnable
匿名类。
所以这两个 Runnable
实例的同步不会对同一个锁进行操作。
您必须在外部类实例上同步以锁定同一监视器,例如:
synchronized (Test.this) {...}
此外,请注意,通过使用 lambda 来实现 Runnable
功能接口(interface),例如:
var writer = () -> {
synchronized (this) {
System.out.println("condition is set to true");
condition = true;
}
};
您可以保留实际语法(synchronized (this)
),因为在这种情况下 this
不引用不存在的匿名类,而是引用外部类实例。
关于java:同步块(synchronized block)可以交错吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50356140/