登录  /  注册
首页 > 常见问题 > 正文

hashset线程安全吗?

anonymity
发布: 2019-04-25 13:38:42
原创
13835人浏览过

什么是线程安全,就是对于数据的读写要线程隔离,不能导致数据的丢失和不一致,每次修改数据都不应该被覆盖掉。 

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

hashset线程安全吗?

这次我们来证明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中文网其它相关文章!

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
相关标签:
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
关于CSS思维导图的课件在哪? 课件
凡人来自于2024-04-16 10:10:18
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号