我有一个意外(至少对我来说)输出此代码
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
(进入同步块)this
锁,进入自己的同步块但是,在某些代码运行中,我得到了输出
waiting for condition
condition is set to true
condition is true
我是否遗漏了某些内容或者我误解了同步块/方法的工作原理?
答案 0 :(得分:3)
两个synchronized (this)
语句引用Runnable
个匿名类
因此,两个Runnable
实例的同步不会在同一个锁上运行
您必须在外部类实例上进行同步才能锁定同一监视器,例如:
synchronized (Test.this) {...}
此外,请注意,通过使用lambda来实现Runnable
功能接口,例如:
var writer = () -> {
synchronized (this) {
System.out.println("condition is set to true");
condition = true;
}
};
您可以将实际语法(synchronized (this)
)保留为this
,在这种情况下,不会引用不存在但引用外部实例的匿名类。
答案 1 :(得分:2)
在您的代码中,synchronized(this)
指的是两个不同的对象。因此,两个代码都不会阻塞另一个,它们只是同时运行。
另一种看待它的方法是不使用var
或本地类。只需声明两个与reader
和writer
完全相同的顶级类:
// var reader = new Runnable() {
class Reader implements 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() {
class Writer implements Runnable {
@Override
public void run() {
synchronized (this) {
System.out.println("condition is set to true");
condition = true;
}
}
}
很明显,this
在这种情况下是指每个类的实例,而不是同一个对象,因此这两个类永远不会相互阻塞。
答案 2 :(得分:2)
引用this
引用当前对象。在内部类this
的实例方法内部引用内部类的当前对象。如果你想访问外部封闭类的当前对象,那么你需要使用:OuterClassName.this
。
在您的情况下,您有两个具有匿名类的单独对象。同步块不共享要锁定的公共对象,所以实际上没有同步,而是两个线程独立并行运行。