hashset线程安全吗?
什么是线程安全,就是对于数据的读写要线程隔离,不能导致数据的丢失和不一致,每次修改数据都不应该被覆盖掉。
还是举银行取款的经典例子,账户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中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Java中使用HashSet.remove()方法可以从集合中删除指定元素。HashSet是一个实现了Set接口的集合类,它不允许存储重复元素,且不保证元素顺序。在操作HashSet时,可以使用remove()方法来删除集合中的元素。HashSet的remove()方法有两种重载形式:booleanremove(Objectobj):从集合中删除指定对象

Java中的HashSet函数是一个基于哈希表实现的集合类。既然是集合类,那么它自然拥有集合操作的功能,本文将介绍如何使用HashSet函数进行集合操作。一、HashSet的定义与声明HashSet是一个集合类,因此首先需要导入Java.util包。importjava.util.HashSet;然后就可以创建一个HashSet实例:HashSet<

Java文档解读:HashSet类的contains()方法用法详解HashSet类是Java中常用的集合类之一,它实现了Set接口,并且基于哈希表的数据结构,具有高效的插入、删除和查找操作。其中,contains()方法是HashSet类提供的一个重要方法,用于判断集合中是否包含指定的元素。本文将详细解析HashSet类的contains()方法的用法,并

Java中使用HashSet.add()方法添加元素到集合中非常简单,下面我们来详细介绍一下。HashSet是Java中的一个集合类,它继承自AbstractSet类并实现了Set接口,HashSet的特点是无序、不重复,底层实现是基于哈希表的。在使用HashSet.add()方法添加元素时,需要注意以下几点:HashSet中只能存储对象类型的元素,不能存储

使用HashSet类的addAll()方法将一个集合中的所有元素添加到另一个集合中HashSet是Java集合框架中的一个实现类,它继承自AbstractSet,并实现了Set接口。HashSet是一个基于哈希表的无序集合,其中不允许包含重复的元素。它提供了许多常用的方法来操作集合中的元素,其中之一就是addAll()方法。addAll()方法的作用是将指定

使用HashSet类的addAll()方法将一个集合添加到另一个集合中HashSet是Java中的一个集合类,它实现了Set接口,底层基于哈希表实现。HashSet集合中不允许有重复元素,并且集合中的元素是无序的。在开发中,我们常常需要将一个集合中的元素添加到另一个集合中。HashSet类提供了addAll()方法,可以方便地实现这个功能。下面我们将通过一个

HashSet类图HashSet简单说明1.HashSet实现了Set接口2.HashSet底层实际上是由HashMap实现的publicHashSet(){map=newHashMap();}3.可以存放null,但是只能有一个null4.HashSet不保证元素是有序的(即不保证存放元素的顺序和取出元素的顺序一致),取决于hash后,再确定索引的结果5.不能有重复的元素HashSet底层机制说明HashSet底层是HashMap,HashMap底层是数组+链表+红黑树模拟数组+链表的结构/*

HashSet是Java中提供的一个非常常用的集合类,它可以存储一组不重复的、无序的元素。在使用HashSet时,有时候需要将HashSet中的元素转化为数组,这时候就需要用到其提供的toArray()方法。下面我们就来详细解读一下HashSet类的toArray()方法的用法,同时也提供一些具体的代码示例。首先,我们来看一下toArray()方法的定义: