如何在HashMap中演示竞争条件?

时间:2017-12-01 03:46:59

标签: java concurrency thread-safety

我正在用Java教授并发编程,并希望向学生展示使用非线程安全数据结构可能出现的问题。我创建了以下程序:

    Map<String,String> favoriteFoods = new HashMap<>();
    Thread t1 = new Thread(() -> {
        favoriteFoods.put("Alice","avocado");
        favoriteFoods.put("Bob","banana");
    });
    Thread t2 = new Thread(() -> {
        favoriteFoods.put("Alice","aloysia");
        favoriteFoods.put("Carl","candy");
    });
    t1.start();
    t2.start();

    t1.join();
    t2.join();
    System.out.println(favoriteFoods);

从两个不同的线程访问非线程安全的HashMap。但是,每次运行程序都可以正常运行。

如何更改代码以证明问题?

3 个答案:

答案 0 :(得分:2)

尝试使用哈希冲突向HashMap添加元素:

import java.util.*;
public class HashMapRaceCondition2 {
    public static void main(String[] args) throws Exception {
        class MyClass {
            int value;

            MyClass(int value) {
                this.value = value;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;

                MyClass myClass = (MyClass) o;

                if (value != myClass.value) return false;

                return true;
            }

            @Override
            public int hashCode() {
                return 42;
            }

            @Override
            public String toString() {
                return "MyClass{" +
                        "value=" + value +
                        '}';
            }
        }  // MyClass

        Map<MyClass,Integer> map = new HashMap<>();

        Thread t1 = new Thread(() -> {
            for (int i =0; i < 1000; ++i) {
                map .put(new MyClass(i), i);
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 2000; i < 3000; ++i) {
                map.put(new MyClass(i), i);
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(map.size());
    }
}

此代码在每5-6次执行时在我的机器上失败。

答案 1 :(得分:1)

例如:

Map<Integer, Integer> map = new HashMap<>(1);

    IntStream.range(0, 100)
            .parallel()
            .map(x -> {
                map.put(x, x);
                return x;
            })
            .max();

    System.out.println(map.size());

运行几次,结果不会一直100

答案 2 :(得分:0)

恕我直言,你的第一个代码应该展示竞争状态而不进行任何进一步的改变。我试了几次,有时爱丽丝'是'鳄梨,有时候爱丽丝'是'aloysia。我认为你所谓的正确答案(在这种情况下,Alisia只映射到鳄梨或只用于aloysia)是由于超快速的多核计算机。您可以询问学生中的某个人是否可以在某些较旧的硬件中运行您的代码。