当前位置:网站首页>并发的基本概念,操作,容器
并发的基本概念,操作,容器
2022-08-10 08:58:00 【努 力 小 子】
文章目录
基本概念
并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
并发Concurrent和并行Parallel的区别
并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。这种方式我们称之为并发(Concurrent)。
并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
JDK提供的容器类
JDK 提供的这些容器大部分在 java.util.concurrent 包中。
ConcurrentHashMap: 线程安全的 HashMap
CopyOnWriteArrayList: 线程安全的 List,在读多写少的场合性能非常好,远远好于 Vector. ConcurrentLinkedQueue: 高效的并发队列,使用链表实现。可以看做一个线程安全的
LinkedList,这是一个非阻塞队列。
BlockingQueue: 这是一个接口,JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队
列,非常适合用于作为数据共享的通道。
ConcurrentSkipListMap: 跳表的实现。这是一个 Map,使用跳表的数据结构进行快速查找。
ConcurrentHashMap
HashMap 不是线程安全的,在并发场景下可用Collections.synchronizedMap() 方法包装HashMap。但通过使用一个全局的锁来同步不同线程间的并发访问会带来不可忽视的性能问题。HashMap 的线程安全版本ConcurrentHashMap 无论是读操作还是写操作都能保证很高的性能:在进行读操作时(几乎)不需要加锁,而在写操作时通过锁分段技术只对所操作的段加锁而不影响客户端对其它段的访问。
CopyOnWriteArrayList
很多应用场景中,读操作可能会远远大于写操作。由于读操作根本不会修改原有的数据,因此对于每次读取都进行加锁其实是一种资源浪费。我们应该允许多个线程同时访问 List 的内部数据,毕竟读取操作是安全的。
CopyOnWriteArrayList 读取是完全不用加锁的,并且写入也不会阻塞读取操作。只有写入和写入之间需要进行同步等待。这样一来,读操作的性能就会大幅度提升。
CopyOnWriteArrayList 类的所有可变操作(add,set 等等)都是通过创建底层数组的新副本来实现的。当 List 需要被修改时并不修改原有内容,而是对原有数据进行一次复制,将修改的内容写入副本。写完之后,再将修改完的副本替换原来的数据,这样就可以保证写操作不会影响读操作了。 CopyOnWrite 就是想要对一块内存进行修改时不在原有内存块中进行写操作,而是将内存拷贝一份,在新的内存中进行写操作,写完之后呢,就将指向原来内存指针指向新的内存,原来的内存就可以被回收掉了。
CopyOnWriteArrayList 写入操作 add() 方法在添加集合的时候加了锁,保证了同步,避免了多线程写的时候会 copy 出多个副本出来。
阻塞队列BlockingQueue和非阻塞队列ConcurrentLinkedQueue
线程安全的 Queue 可以分为阻塞队列和非阻塞队列,阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是 ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。 阻塞队列可以通过加锁来实现,非阻塞队列可以通过 CAS 操作实现。
阻塞队列BlockingQueue
阻塞队列(BlockingQueue)被广泛使用在“生产者-消费者”问题中,提供了可阻塞的插入和移除的方法。当队列容器已满,生产者线程会被阻塞,直到队列未满;当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。BlockingQueue 是一个接口,继承自 Queue,所以其实现类也可以作为 Queue 的实现来使用,而Queue 又继承自 Collection 接口。
阻塞队列BlockingQueue的三个实现类
ArrayBlockingQueue
ArrayBlockingQueue 是 BlockingQueue 接口的有界队列实现类,底层采用数组来实现。ArrayBlockingQueue 一旦创建,容量不能改变。其并发控制采用可重入锁来控制,不管是插入操作还是读取操作,都需要获取到锁才能进行操作。当队列容量满时,尝试将元素放入队列将导致操作阻塞;尝试从一个空队列中取一个元素也会同样阻塞。
ArrayBlockingQueue 默认情况下不能保证线程访问队列的公平性,所谓公平性是指严格按照线程等待的绝对时间顺序,即最先等待的线程能够最先访问到 ArrayBlockingQueue。而非公平性则是指访问ArrayBlockingQueue 的顺序不是遵守严格的时间顺序。如果保证公平性,通常会降低吞吐量。
LinkedBlockingQueue
LinkedBlockingQueue 底层基于单向链表实现的阻塞队列,可以当做无界队列也可以当做有界队列来使用,同样满足公平性 FIFO 的特性,与ArrayBlockingQueue 相比起来具有更高的吞吐量,为了防止LinkedBlockingQueue 容量迅速增,损耗大量内存。通常在创建LinkedBlockingQueue 对象时,会指定其大小,如果未指定,容量等于Integer.MAX_VALUE。
PriorityBlockingQueue
PriorityBlockingQueue 是一个支持优先级的无界阻塞队列。默认情况下元素采用自然顺序进行排序,也可以通过自定义类实现 compareTo() 方法来指定元素排序规则,或者初始化时通过构造器参数Comparator 来指定排序规则。PriorityBlockingQueue 并发控制采用的是 ReentrantLock,队列为无界队列(ArrayBlockingQueue是有界队列,LinkedBlockingQueue 也可以通过在构造函数中传入 capacity 指定队列最大的容量,但是PriorityBlockingQueue 只能指定初始的队列大小,后面插入元素的时候,如果空间不够的话会自动扩容)。
简单地说,它就是 PriorityQueue 的线程安全版本。不可以插入 null 值,同时,插入队列的对象必须是可比较大小的(comparable),否则报ClassCastException 异常。它的插入操作 put 方法不会block,因为它是无界队列(take 方法在队列为空的时候会阻塞)。
非阻塞队列ConcurrentLinkedQueue
ConcurrentLinkedQueue 这个队列使用链表作为其数据结构,应该算是高并发环境中性能最好的队列了。它之所有能有很好的性能,是因为其内部复杂的实现。ConcurrentLinkedQueue 主要使用CAS 非阻塞算法来实现线程安全,适合在对性能要求相对较高,同时对队列的读写存在多个线程同时进行的场景,即如果对队列加锁的成本较高则适合使用无锁的 ConcurrentLinkedQueue 来替代。
边栏推荐
- Solve the problem that the win10win7win8 system cannot find the specified module and cannot register the desert plug-in
- 幂次方(暑假每日一题 20)
- 【 WeChat applet 】 read page navigation
- m.bjhjwy.com全面教学设备 类型包括: 教学仪器, 教学设备 ,
- How AliExpress sellers seize product search weight
- 数据库注入提权总结(一)
- js reads excel time format conversion
- Johnson全源最短路
- Ask next CDC mysql to Doris. Don't show the specific number of lines, how to do?
- Rust learning: 6.5_Array of composite types
猜你喜欢

Rust learning: 6.3_ Tuples of composite types

多线程浅谈

数据库注入提权总结(一)

PTA 习题2.2 数组循环左移

iwemeta metaverse: a doll sells for 9999 yuan, and Bubble Mart thinks it is not expensive at all

J9 Number Theory: Macro Analysis of DAO Characteristics

【搜索引擎】Solr:提高批量索引的性能

CV+Deep Learning - network architecture Pytorch recurrence series - classification (3: MobileNet, ShuffleNet)

多线程知识点总结之温故而知新

Solve the problem that the win10win7win8 system cannot find the specified module and cannot register the desert plug-in
随机推荐
JVM探究
CTFSHOW七夕杯web
ShardingSphere入门
地平线:面向规模化量产的智能驾驶系统和软件开发
推荐几个高质量的软件测试实战项目
qrcode-----生成二维码
浅谈DAO+DeFi+NFT模式开发代码技术方案丨链游元宇宙NFT盲盒项目技术开发逻辑(源码程序)
Solve the problem that the win10win7win8 system cannot find the specified module and cannot register the desert plug-in
dayjs-----time format
mySQL add, delete, modify and check advanced
Vivado时序约束中Tcl命令的对象及属性
In the SQL SERVER database, if the data of the table is added, deleted, or modified, will the index of the table be recorded in the ldf log?
DAY25: Logic vulnerability recurrence
Rust learning: 6.3_ Tuples of composite types
英伟达游戏显卡营收暴跌/ 谷歌数据中心爆炸致3人受伤/ iPhone电量百分比回归…今日更多新鲜事在此...
浅析JWT安全问题
【API架构】使用 JSON API 的好处
【Unity入门计划】制作RubyAdventure03-使用碰撞体&触发器实现世界交互
【REST架构】OData、JsonAPI、GraphQL 有什么区别?
Johnson全源最短路