IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> 集合类不安全 -> 正文阅读

[开发工具]集合类不安全

代码:

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

// ConcurrentModificationException
public class ListTest {
    public static void main(String[] args) {
        //并发下 ArrayList 不安全
        /**
         * 解决方案:
         * 1.使用Vector 解决 List<String> list = new Vector<>();
         * 2.使用 Collections.synchronizedList
         * List<String> list = Collections.synchronizedList(new ArrayList<>());
         * 3.List<String> list = new CopyOnWriteArrayList<>();
         */
        /*CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略
            多个线程调用的时候 list 读取 的时候 国定的 写入(覆盖)
            在写入的时候避免覆盖,造成数据问题
            读写分离
         */
        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i < 13; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

那CopyOnWriteArrayList于Vector区别在哪里:

?Vector:

可以发现?CopyOnWriteArrayList采用的是Lock锁而Vector采用的是synchronized锁?

set

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 同理可证: ConcurrentModificationException
 * 解决方案1: Set<String> set = Collections.synchronizedSet(new HashSet<>());
 * 解决方案2: Set<String> set = new CopyOnWriteArraySet();
 */
public class SetTest {
    public static void main(String[] args) {
        //Set<String> set = new HashSet<>();
        //Set<String> set = Collections.synchronizedSet(new HashSet<>());
        Set<String> set = new CopyOnWriteArraySet();
        for (int i = 1; i < 15; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
    }
}

?hashset的底层是什么?

切入源码会发现:

?底层是HashMap

set的add方法?

private static final Object PRESENT = new Object(); 不可变的值
本质是map key? 不可以重复

map

?1<<4 = 16


import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

//ConcurrentModificationException
public class MapTest {
    public static void main(String[] args) {
        // map 是这样用的吗?
        //默认等价于什么? new HashMap<>(16,0.75);//加载因子,初始化容量
        /*
          1. Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
          2.Map<String, String> map = new ConcurrentHashMap<>();
         */
        Map<String, String> map = new ConcurrentHashMap<>();

        for (int i = 1; i < 20; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }

}

那么ConcurrentHashMap有是什么呢:

api中这样说:

  • 支持检索的完全并发性和更新的高预期并发性的哈希表。 这个类服从相同功能规范如Hashtable ,并且包括对应于每个方法的方法版本Hashtable 。 不过,尽管所有操作都是线程安全的,检索操作并不意味着锁定,并没有为防止所有访问的方式锁定整个表的任何支持。 这个类可以在依赖于线程安全性的程序中与Hashtable完全互Hashtable ,但不依赖于其同步细节。

    检索操作(包括get )通常不阻止,因此可能与更新操作重叠(包括putremove )。 检索反映了最近完成的更新操作的结果。 (更正式地,对于给定密钥的更新操作熊之前发生与任何(非空关系)检索该键报告经更新的值。)对于聚合操作,比如putAllclear ,并发检索可能反映插入或移除只有一些条目。 类似地,迭代器,分割器和枚举返回在反映迭代器/枚举创建过程中或之后反映哈希表状态的元素。 他们抛出ConcurrentModificationException 。 然而,迭代器被设计为一次只能由一个线程使用。 请记住,骨料状态方法的结果,包括sizeisEmptycontainsValue通常是有用的,只有当一个地图没有发生在其他线程并发更新。 否则,这些方法的结果反映了可能足以用于监视或估计目的的瞬态状态,但不适用于程序控制。

    当存在太多的冲突(即,具有不同的哈希码但是以表的大小为模数落入相同的时隙的密钥)时,该表被动态扩展,并且每个映射保持大致两个bin的预期平均效果(对应于0.75负载因素阈值调整大小)。 由于映射被添加和删除,这个平均值可能会有很大差异,但是总的来说,这为哈希表保留了普遍接受的时间/空间权衡。 然而,调整这个或任何其他类型的散列表可能是相对较慢的操作。 如果可能,最好提供一个尺寸估计作为可选的initialCapacity构造函数参数。 附加的可选的loadFactor构造函数参数提供了另外的手段,通过指定在计算给定数量的元素时要分配的空间量时使用的表密度来定制初始表容量。 此外,为了与此类的先前版本兼容,构造函数可以可选地指定预期的concurrencyLevel作为内部大小调整的附加提示。 请注意,使用完全相同的许多键hashCode()是降低任何哈希表的hashCode()的一种可靠的方法。 为了改善影响,当按键为Comparable时,该类可以使用键之间的比较顺序来帮助打破关系。

    Set投影一个的ConcurrentHashMap可以(使用被创建newKeySet()newKeySet(int) ),或观察(使用keySet(Object)时仅键是感兴趣的,并且被映射的值是(可能瞬时)不使用或全部取相同的映射值。

    ConcurrentHashMap可以通过使用LongAdder值并通过computeIfAbsent进行初始化,将其用作可缩放的频率映射(直方图或多集的形式)。 例如,要向ConcurrentHashMap<String,LongAdder> freqs添加计数,可以使用freqs.computeIfAbsent(k -> new LongAdder()).increment();

    此类及其视图和迭代器实现所有的可选方法MapIterator接口。

    Hashtable但不像HashMap ,这个类不允许 null用作键或值。

    ConcurrentHashMaps支持一组顺序和并行批量操作,与大多数Stream方法不同,它们被设计为安全并且经常明智地应用,即使是由其他线程同时更新的映射; 例如,当计算共享注册表中的值的快照摘要时。 有三种操作,每种具有四种形式,接受键,值,条目和(键,值)参数和/或返回值的函数。 由于ConcurrentHashMap的元素不以任何特定的方式排序,并且可能会在不同的并行执行中以不同的顺序进行处理,因此提供的函数的正确性不应取决于任何排序,也不应依赖于可能瞬时变化的任何其他对象或值计算进行中; 除了每一个行动,理想情况下都是无副作用的。 对Map.Entry对象的批量操作不支持方法setValue

    • forEach:对每个元素执行给定的操作。 变量形式在执行操作之前对每个元素应用给定的变换。
    • search:返回在每个元素上应用给定函数的第一个可用非空结果; 当找到结果时跳过进一步的搜索。
    • reduce:累积每个元素。 提供的减少功能不能依赖于排序(更正式地,它应该是关联和交换)。 有五种变体:
      • 平原减少 (由于没有相应的返回类型,因此(key,value)函数参数没有这种方法的形式)
      • 映射的减少积累了应用于每个元素的给定函数的结果。
      • 使用给定的基础值减少到标量双,长和int。

    这些批量操作接受一个parallelismThreshold参数。 如果估计当前地图大小小于给定阈值,则方法依次进行。 使用Long.MAX_VALUE的值Long.MAX_VALUE抑制所有的并行性。 使用1的值可以通过划分为足够的子任务来完全利用用于所有并行计算的ForkJoinPool.commonPool()来实现最大并行度。 通常,您最初将选择其中一个极值,然后测量使用中间值之间的性能,从而降低开销与吞吐量之间的关系。

    批量操作的并发属性遵循ConcurrentHashMap的并发属性:从get(key)返回的任何非空结果和相关的访问方法与相关的插入或更新都有一个发生之前的关系。 任何批量操作的结果都反映了这些每个元素关系的组成(但是除非以某种方式已知是静态的,它们并不一定是相对于整个地图的原子)。 相反,因为映射中的键和值从不为空,所以null作为目前缺乏任何结果的可靠原子指标。 为了保持此属性,null用作所有非标量缩减操作的隐含基础。 对于double,long和int版本,基础应该是当与任何其他值组合时返回其他值(更正式地,它应该是减少的标识元素)。 大多数常见的减少具有这些属性; 例如,使用基数0或最小值与基准MAX_VALUE计算和。

    作为参数提供的搜索和转换函数应该类似地返回null以指示缺少任何结果(在这种情况下不被使用)。 在映射缩减的情况下,这也使得转换可以用作过滤器,如果不应该组合元素,返回null(或者在原始专业化的情况下,身份基础)。 在使用它们进行搜索或减少操作之前,您可以通过在“null意味着现在没有任何内容”规则下自行构建复合转换和过滤。

    接受和/或返回Entry参数的方法维护键值关联。 例如,当找到最大价值的钥匙时,它们可能是有用的。 请注意,可以使用new AbstractMap.SimpleEntry(k,v)提供“plain”Entry new AbstractMap.SimpleEntry(k,v)

    批量操作可能突然完成,抛出在应用程序中遇到的异常。 在处理这样的异常时,请注意,其他并发执行的函数也可能引发异常,或者如果没有发生第一个异常,则会这样做。

    与顺序形式相比,加速比是常见的,但不能保证。 如果并行计算的基础工作比计算本身更昂贵,则涉及小地图上的简短功能的并行操作可能比顺序形式执行得更慢。 类似地,如果所有处理器正忙于执行不相关的任务,并行化可能不会导致太多的实际并行。

    所有任务方法的所有参数都必须为非空值。

推荐视频:【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 15:56:38  更:2022-05-01 15:56:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:46:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码