我寫了一個擴展線程的內部私有類的類。我的外部類啓動此線程的一個實例,並且該線程訪問循環內的外部類的字段。但是,外部代理可能會調用外部類的方法來修改外部類的字段。這些方法必須與線程內部的循環同步,以便修改不會干擾循環。爲什麼兩個同步塊像我一樣提供了不同的監視器對象,當兩個監視器域引用相同的對象時?
我一直在使用外部類(Android SurfaceHolder)的字段上的「synchronized」塊進行同步,將此對象傳遞給內部類並將其引用存儲爲內部類中的字段,然後同步在線程循環中的內部類字段上。然而,這導致外部類方法在內部類應該被鎖定時運行的行爲!我試圖刪除內部字段和內部類鎖定在外部類完全相同的領域,並且一切正常。
所以,這裏是一個問題:我通過檢查==運算符並查看字符串表示來驗證內部和外部字段指向的對象是相同的對象,那麼爲什麼同步塊在此行爲就像我使用兩個不同的對象一樣?也許我對同步塊的工作方式有一個基本的誤解?
編輯:
好吧,我得到了很多downvotes,但評論者似乎只是希望有更多的細節,我決心要明白我沒有得到這裏。我會回覆每條評論。在這裏,開始,是我在做什麼的例子:
class Outer {
private Object lock;
private Foo foo;
public Outer() {
lock = new Object();
// The thread is actually started in an Android callback method,
// but I'll start it here as a demonstration
InnerThread thread = new InnerThread(lock);
thread.setRunning(true);
thread.start();
}
private void modifyFoo() {
synchronized(lock) {
Log.d("outer", "locked outer");
foo.bar(); // Has some effect on foo
}
Log.d("outer", "released outer");
}
private class InnerThread extends Thread {
private volatile boolean running = false;
private Object lock;
public InnerThread(Object lock) {
this.lock = lock;
}
private void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while(running) {
synchronized(lock) {
Log.d("inner", "locked inner");
foo.blah(); // Has some effect on foo
}
Log.d("inner", "released inner");
}
}
}
}
意外的行爲是,當我稱之爲modifyFoo()
方法與線程運行,我看到了下面的日誌輸出:
locked inner
released inner
locked inner
released inner
locked inner
locked outer
released outer
released inner
一個響應指出「你永遠不應該擴展線程」和「你似乎有一個對象在一個字段和外部對象本身」。首先,我擴展了Thread,因爲它是Android SurfaceView示例中使用的方法。我不知道如何重寫run()
方法;我應該將一個runnable傳遞給線程嗎?其次,正如我所理解的那樣,內部和外部類中的lock
字段都持有對lock = new Object();
行上創建的同一實例的引用。我不是問這應該如何組織;我正在問具體爲什麼同步塊看起來像查看對不同對象的同一對象的這兩個引用。
要添加一些上下文,這是一個使用Android的SurfaceView類的項目。我儘量靠近Android提供的LunarLander項目,其中他們用於鎖定的SurfaceHolder對象被傳遞到線程構造函數中,並通過引用存儲在其中。這可能是奇怪結構的原因。
如果你可以發佈你的代碼,那就太好了。 –
理想情況下,作爲一個簡短但完整的程序演示該問題... –
請閱讀[如何創建MCVE](http://stackoverflow.com/help/mcve)。 – assylias