HastSet< String>线程安全 [英] HastSet<String> thread safe

查看:81
本文介绍了HastSet< String>线程安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

===更新====

===update====

来自评论

所以我清楚地阅读了该文档,并且知道它不是线程安全的,我想进行一个小实验来看看它会如何破裂.因此,医生说结果是不确定的.有人知道会发生什么吗?如果我想证明它不是线程安全的,该如何编写示例代码,以便实际上可以看到它不是线程安全的?你们有没有尝试过并且没有看到有效的例子?你有示例代码吗?

so I clearly read the doc and know it's not thread safe and I wanted to run a small experiment to see how it will break. So the doc says the result is non deterministic. Does anyone know what could happen? If I want to prove it's not thread safe how can I write a sample code so that I can actually see that it's no thread safe? Have you guys actually tried and seen not working example? Do you have sample code?

如果我有三个线程访问字符串的哈希集.

If I have three threads accessing the hashset of string.

  • 一个添加新字符串的人
  • 第二次删除字符串
  • 第三次删除所有

HashSet线程安全吗?

Is the HashSet thread safe?

public void test()
{
    Set<String> test = new HashSet<>();
    Thread t0= new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                boolean c = test.contains("test");
                System.out.println("checking " + c);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                test.add("test");
                System.out.println("adding");
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
                if (!test.isEmpty())
                {
                    test.removeAll(test);
                }
                System.out.println("removing");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    });
    t0.start();
    t1.start();
    t2.start();

    while(true) {

    }
}

我有此测试代码并运行了它,似乎可以正常工作.没有异常被抛出.我有点困惑,因为HashSet不是线程安全的. 我想念什么?

I have this test code and ran it and it seems working. No exceptions were thrown. I was little confused because HashSet is not thread-safe. Whay am I missing?

推荐答案

来自评论:

所以我清楚地阅读了该文档,并且知道它不是线程安全的,我想进行一个小实验来看看它会如何破裂.因此,医生说结果是不确定的.有人知道会发生什么吗?如果我想证明它不是线程,我如何编写示例代码,以便实际上可以看到它不是线程安全的?你们是否真的尝试过并看到不起作用的示例?你有示例代码吗?

so I clearly read the doc and know it's not thread safe and I wanted to run a small experiment to see how it will break. So the doc says the result is non deterministic. does anyone know what could happen? If I want to prove it's not thread how cam I write a sample code so that I can actually see that it's no thread safe? Have you guys actually tried and seen that not working example? do you have sample code?

问题在于更新Set可能不是原子操作,尤其是当内部哈希表需要调整大小时更是如此.

The problem is that updating the Set may not be an atomic operation, especially not when the internal hash table needs to be re-sized.

如果两个线程同时在更新,您可能会得到一个简单的结果,一个线程会覆盖另一个线程的更改,因此您将丢失一个更改.更严重的是,冲突可能损坏 Set的内部结构.

If two threads are updating at the same time, you may get the simple result that one thread overrides the change by the other thread, so you lose a change. More seriously, the conflict may corrupt the internal structure of the Set.

为了说明这一点,这是一个小程序,在添加值时会引起高度冲突.所有添加的值都是不同的,因此应该全部添加,但是您会看到Set的大小在编程完成后是不正确的,证明有些添加的值丢失了.

To show this, here is a small program that causes high conflict during add of values. All values added are distinct, so they should all be added, but you will see that size of the Set is incorrect when program is done, proving that some added values got lost.

final int THREAD_COUNT = 10;
final int NUMS_TO_ADD = 100000;
Set<Integer> set = new HashSet<>();
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
    final int threadNo = i;
    threads[i] = new Thread() {
        @Override public void run() {
            for (int j = 0; j < NUMS_TO_ADD; j++)
                set.add(j * THREAD_COUNT + threadNo); // all distinct values
        }
    };
    threads[i].start();
}
for (int i = 0; i < threads.length; i++)
    threads[i].join();
System.out.println("Found " + set.size() + " values, expected " + THREAD_COUNT * NUMS_TO_ADD);

每次运行它,都会得到不同的结果,例如

Each time you run it, you will get a different result, e.g.

Found 898070 values, expected 1000000

Found 825773 values, expected 1000000

Found 731886 values, expected 1000000

Exception in thread "Thread-7" java.lang.ClassCastException: java.base/java.util.HashMap$Node cannot be cast to java.base/java.util.HashMap$TreeNode
    at java.base/java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1883)
    at java.base/java.util.HashMap$TreeNode.putTreeVal(HashMap.java:2063)
    at java.base/java.util.HashMap.putVal(HashMap.java:638)
    at java.base/java.util.HashMap.put(HashMap.java:612)
    at java.base/java.util.HashSet.add(HashSet.java:220)
    at Test$1.run(Test.java:16)

或者该程序只是挂起!

这篇关于HastSet&lt; String&gt;线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆