• 技术文章 >常见问题

    hashset线程安全吗?

    anonymityanonymity2020-09-10 13:16:58原创6034
    什么是线程安全,就是对于数据的读写要线程隔离,不能导致数据的丢失和不一致,每次修改数据都不应该被覆盖掉。

    还是举银行取款的经典例子,账户A起初为0,线程A读出0,然后存100(还没写入数据),线程B读出为0,也存100,这个时候最后的账户我们看到的是余额100。这是不科学的,这就叫线程不安全。所以我们要控制存取款的对象,让我们操作数据的对象加锁,更新完数据,其他的线程才能,达到线程安全。

    这次我们来证明HashSet,我们知道实现了Set接口。Set的特点就是存放的数据不会重复。因为它的内部会首先读内部保存的数据,是否存在,如果存在就不存放进去,否则存放进去。也就是说数据的存入操作是分两步,首先读取,然后写入。假设不是线程安全,那很可能出现的一种情形就是当线程A判断该set对象没有某个元素,正准备将该元素插入之前,线程B也判断该对象不存在该元素,也准备插入,最后的结果导致了两个相同的元素被插入了。

    我们这样来设计demo:

    class TestHashSet implements Runnable{
        // 实现Runnable 让该集合能被多个线程访问
        Set<Integer> set = new HashSet<Integer>();
        // 线程的执行就是插入5000个整数
        @Override
        public void run() {
            for (int i = 0;i < 5000;i ++) {
                set.add(i);
            }
        }
    }

    我们在主线程来测试:

      TestHashSet run2 = new TestHashSet();
            // 实例化两个线程
            Thread t6 = new Thread(run2);
            Thread t7 = new Thread(run2);
            // 启动两个线程
            t6.start();
            t7.start();
            // 当前线程等待加入到调用线程后
            t6.join();
            t7.join();
            // 打印出集合的size
            System.out.println(run2.set.size());

    打印结果大部分是预期的5000,但是偶尔会出现大于5000的情况。这就出现了之前提到的情况,证明了HashSet不是线程安全的类。

    其实查看源代码发现HashSet内部维护数据的采用的是HashMap,根本原因是HashMap不是线程安全的类。导致了HashSet的非线程安全。更多java集合类的知识请关注【PHP中文网:java视频

    最后来一个完整的代码案例验证:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    /**
     * 验证HashSet不是线程安全
     */
    public class HashSetTest {
        public static void main(String[] args) {
            final Set<Integer> set = new HashSet<>();// 结果可能大于1000
    //        final Set<Integer> set = Collections.synchronizedSet(new HashSet<>());// 结果等于1000
    //        final Set<Integer> set = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());// 结果等于1000
            // 往set写入1-1000
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i <= 1000; i++) {
                        set.add(i);
                    }
                }
            };
            int threadNum = 10;// 线程数
            List<Thread> threadList = new ArrayList<>();
            for (int i = 0; i < threadNum; i++) {
                Thread thread = new Thread(runnable);
                threadList.add(thread);
                thread.start();
            }
            // 主线程等待子线程执行完成
            for (Thread thread : threadList) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(set.size());// 结果可能大于1000
        }
    }

    以上就是hashset线程安全吗?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文原创发布php中文网,转载请注明出处,感谢您的尊重!如有疑问,请联系admin@php.cn处理
    专题推荐:hashset
    上一篇:电脑常用快捷键有哪些 下一篇:电脑图标右上角有两个箭头怎么办?
    线上培训班

    相关文章推荐

    • HashSet HashTable 与 TreeSet• java提高篇(二四)-----HashSet• Java集合之HashSet的详细介绍• Core Java简单介绍HashSet

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网