簡體   English   中英

同步哈希圖訪問

[英]Synchronized hashmap access

在我的計算機上,使用Java 8,即使同步了地圖訪問,以下程序也不會停止。 那些同步的塊難道不是嗎?

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

// Broken! - How long would you expect this program to run?
public class StopThread {
    private static HashMap<String, String> stopRequested = new HashMap<String, String>();

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                synchronized (stopRequested) {
                    while (stopRequested.get("stop") == null)
                        i++;
                }
                System.out.println(i);
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        synchronized (stopRequested) {
            stopRequested.put("stop", "true");
        }
    }
}

這將永遠運行。 同步塊中的while循環實際上是無限的,因為它首先被輸入-從而禁止再輸入第二個同步塊。

是的,這是預料之中的,您的backgroundThread在主線程之前持有該鎖,並且直到主線程向地圖寫入“停止”時它才會釋放它,主線程需要該鎖將其寫入“停止”,因此基本上這是一個死鎖。

有幾種方法可以解決此僵局,我想您要嘗試的是查看在主線程在映射中寫入“停止”條目之前計數的次數。 您只需在循環的每次迭代中獲取並釋放鎖,這對您的情況就很有意義。

while (stopRequested.get("stop") == null)
    synchronized (stopRequested) {
                i++;
     }

另一種解決方案可能是使用currentHashMap,請查看此鏈接以獲取更多詳細信息

您有兩個線程在stopRequested上同步。 在任何給定時間僅允許運行一個synchronized塊。 因為它幾乎永遠是backgroundThread的情況下synchronized塊第一次運行,它永遠不會退出,因此絕不允許任何其他線程的同步操作stopRequested

確實存在等待通知方法來解決此問題:

    try {
        int i = 0;
        synchronized (stopRequested) {
            while (stopRequested.get("stop") == null) {
                stopRequested.wait();
                i++;
            }
        }
        System.out.println(i);
    } catch (InterruptedException e) {
        throw new RuntimeException(i);
    }

// ...

synchronized (stopRequested) {
    stopRequested.put("stop", "true");
    stopRequested.notify();
}

這樣做的原因是, wait()會暫時自動地釋放同步鎖,從而允許另一個線程在該對象上進行同步。

請注意, 必須在檢查等待條件的循環中調用wait(),因為即使沒有其他稱為notify()線程,wait()有時也會返回。 這種“虛假喚醒”是由於某些系統上線程的性質所致。

行為良好的線程會將整個等待循環放在try / catch塊中,因此該線程在被中斷時將退出。 中斷是來自其他某個線程的請求,要求您的線程停止正在執行的操作並干凈地退出。

感謝所有的答案。 確實,這是一個僵局。 工作同步是

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

// Broken! - How long would you expect this program to run?
public class StopThread {
    private static HashMap<String, String> stopRequested = new HashMap<String, String>();

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (stopRequested())
                    i++;
                System.out.println(i);
            }
        });
        backgroundThread.start();
        TimeUnit.SECONDS.sleep(1);
        synchronized (stopRequested) {
            stopRequested.put("stop", "true");
        }
    }

    static boolean stopRequested()
    {
        synchronized (stopRequested) {
            return stopRequested.get("stop") == null;
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM