[英]java: can synchronized block interleave?
使用此代碼,我有一個意外的(至少對我來說)輸出
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
我錯過了什么或者我誤解了同步塊/方法是如何工作的?
兩個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
在這種情況下並不是指不存在,而是指外實例的匿名類。
在您的代碼中, synchronized(this)
引用兩個不同的對象。 所以兩個代碼都不會阻塞另一個,它們只是同時運行。
另一種看待它的方法是不使用var
或local類。 只需聲明兩個與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
在這種情況下指的是每個類,而不是同一對象的一個實例,因此這兩類永遠無法阻止對方。
引用this
是指當前對象。 在內部類的實例方法中, this
指的是內部類的當前對象。 如果你想訪問外部封閉類的當前對象,那么你需要使用: OuterClassName.this
。
在您的情況下,您有兩個具有匿名類的單獨對象。 同步塊不共享要鎖定的公共對象,因此實際上沒有同步,而是兩個線程獨立並行運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.