同步hashmap访问

时间:2017-05-29 12:20:00

标签: java multithreading hashmap synchronization

在我的计算机上,使用java 8,即使同步地图访问,以下程序也不会停止。 Aren那些同步的块会不会出现?

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");
        }
    }
}

4 个答案:

答案 0 :(得分:2)

这将永远运行。同步块中的while循环实际上是无限的,因为它是首先输入的 - 因此禁止输入第二个同步块。

答案 1 :(得分:1)

是的,这是预期的,你的backgroundThread在主线程之前持有锁,它不会释放它,直到主线程写入&#34;停止&#34;在地图上,主线程需要锁定才能将其写入&#34; stop&#34;所以基本上这是一个死锁。

有几种方法可以解决这个死锁,我的猜测是你要做的是看看在主线程写入之前你计算了多少次&#34;停止&#34;在地图中输入。 您可以在循环的每次迭代中简单地获取和释放锁,这对您的场景有意义。

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

另一个解决方案可能是使用concurrentHashMap,请查看此link以获取更多详细信息

答案 2 :(得分:1)

您在stopRequested上有两个同步线程。在任何给定时间只允许运行一个synchronized块。因为几乎总是这样,backgroundThread的synchronized块首先运行,所以它永远不会退出,因此永远不会允许任何其他线程在stopRequested上同步。

正好存在waitnotify方法来解决此问题:

    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块中,因此线程将在中断时退出。中断是来自其他某个线程的请求,要求您的线程停止正在执行的操作并彻底退出。

答案 3 :(得分:0)

感谢所有答案。实际上,这是一个僵局。工作同步是

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;
        }
    }
}