线程安全的集合类

     

目录

🌳ArrayList

🌳vector

🌳PriorityQueue

🌳HashMap

🍂HashTable

🍂ConcurrentHashMap

🍂区别

🍃加锁的粒度不同

🍃CAS机制

🍃扩容方式


  常用的ArrayList,LinkedList,HashMap,PriorityQueue......,这些集合类在单线程环境下使用并没有问题,但是在多线程环境下使用就可能造成线程安全问题

        解决方法也很明确,1.要么手动在使用时候给方法加synchronized,例如:多线程修改ArrayList中的某个值时,给该方法加锁。2.使用标准库提供的一些线程安全的集合类

下面就介绍一些标准库提供的线程安全的集合类。 

ArrayList

vector

这个时一个比较古老的类,但是也是可以保证线程安全的,使用方法和ArrayList类似。

public class VectorDemo {
    public static void main(String[] args) {
        Vector<Integer> vector = new Vector<>(4);
        //打印容量
        System.out.println(vector.capacity());
        System.out.println("===================");
        //添加元素
        vector.add(12);
        vector.add(15);
        vector.add(29);

        //打印元素和元素个数
        for (Integer x:vector) {
            System.out.println(x);
        }
        System.out.println("有效元素的个数有: "+vector.size());
        System.out.println("===================");
        //删除元素,可指定位置
        vector.remove(1);

        //重新打印元素
        for (Integer x:vector) {
            System.out.println(x);
        }
        System.out.println("有效元素的个数有: "+vector.size());

    }
}

运行结果:

可以看出和ArrayList的使用非常类似,那么Vector是如和实现线程安全的

其实也就是将一些会造成线程安全问题的方法上加锁。 

PriorityQueue

线程安全的队列,我们就可以使用之前学过的BlockingQueue(阻塞队列)

可以参考博客: http://t.csdn.cn/lPMzS

HashMap

多线程使用哈希表,可以使用  HashTable (不推荐),ConcurrentHashMap (推荐)

HashTable

查看源码可以知道,HashTable保证线程安全也是给方法上加上synchronized。 

ConcurrentHashMap

        与HashTabe不同的是,ConcurrentHashMap并不是直接在方法上加锁,而是只在发生哈希冲突的当前节点部分加锁,也就是只锁住一个链表(HashMap是通过数组加链表实现的)。 

这样就避免”白加锁“的尴尬。也能提高程序的效率。

区别

加锁的粒度不同

不同的加锁粒度导致出发锁冲突的概率不同。

        HashTable是针对整个哈希表加锁,在任何的增删查改操作都会触发加锁,也就都有可能出发锁冲突。

       假如这个哈希表,现在有两个线程,插入两个数据,通过哈希计算,一个要插入到 0 下标节点的链表中,一个要插入到 2 下标节点的链表中。我们知道,本质上这个操作是针对不同对象的修改操作,并不会导致线程不安全问题。但是如果使用HashTable来进行这个操作,会直接给插入操作加锁,这样就会导致效率降低,而使用ConcurrentHashMap这个操作就不会触发加锁。只有数两个线程的插入数据操作是针对同一个节点的链表时才会加锁。 

CAS机制

CAS(compare and swap)

是一种cpu指令,本身就是一个原子操作,无需加锁。

通过比较内存数据(a)和寄存器数据(b)如果一致就将 b值 赋予内存(a)。

在ConcurrentHashMap中有很多方法中都使用到了CAS,CAS本身就是原子的,比加锁更高效。

扩容方式

HashTable:当元素超过当前的容量是触发扩容机制,重新申请一个更大的内存空间,然后将原来旧表中的数据重新进行哈希,插入到新表。但是如果旧表中的数据非常庞大,此时触发了扩容,再使用当前的扩容方式就会使当前的插入操作变得非常卡顿

ConcurrentHashMap:同样,当put操作触发扩容机制时,会申请一个更大的内存空间,但是并不会一次性将旧表中的所有数据都重新哈希计算重新插入,而是只搬运一部分数据,后面进行查找操作时,会同时查找新,旧表,插入数据时会在新表进行插入。并且在进行每次操作时,都会将旧表中的数据搬运一部分到新表中

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
除了提供高性能的线程安全集合类java的并发包还提供了以下功能: 1. 并发执行框架:java.util.concurrent包中的Executor框架提供了一种使用线程池的方式来执行并发任务。它将任务的提交与任务的执行解耦,可以通过线程池来管理和复用线程,并提供了任务执行的调度和控制的功能。 2. 并发工具类:并发包中还提供了一些工具类,如CountDownLatch、CyclicBarrier、Semaphore等,用于帮助实现更加复杂的并发控制。这些工具类可以用于同步多个线程的执行,控制线程的并发数量,并在一些条件满足后触发线程的执行等功能。 3. 原子操作类:并发包中提供了一系列原子操作类,如AtomicInteger、AtomicLong等,用于在多线程环境下对变量进行原子操作。这些类通过使用CAS(Compare and Swap)操作来保证变量的原子性,避免了使用synchronized关键字进行同步操作带来的性能开销。 4. 并发线程安全工具类:并发包中还提供了一些线程安全的辅助类,如CopyOnWriteArrayList、ConcurrentHashMap等,用于替代传统的非线程安全集合类。这些类通过使用一些特定的并发算法来保证多线程环境下的线程安全性,能够在并发读写的情况下提供较好的性能。 总之,java的并发包不仅提供了高性能的线程安全集合类,还提供了一些并发执行框架、并发工具类、原子操作类以及线程安全工具类,用于帮助开发者在多线程环境下更加方便、高效地编写并发代码。这些功能的引入使得开发者能够更好地处理并发程序的编写与调试,提高了程序的性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值