美文网首页Android开发技术分享
常用Java线程同步工具类

常用Java线程同步工具类

作者: 珠穆朗玛小王子 | 来源:发表于2021-02-24 18:03 被阅读0次

    前言

    本篇简单介绍Android以及Java提供了的数据并发类。

    什么是锁

    并发锁分为两种,一种是悲观锁synchronized,认为所有的访问都存在竞争关系,所以直接在底层阻塞当前线程,竞争规则不可控,所以效率相对较低。

    第二种是乐观锁:优先非竞争关系,例如首次访问,认为不存在竞争关系,所以只是标记该对象处于访问中,并未加锁,此时第二线程并发访问,认为当前访问者很快就会访问结束,所以原地等待(自旋锁),也并未上锁。乐观锁是上层实现,可控性好,使用得当,效率比悲观锁更高,但是等待时间过长,占用CPU的时间也较多,导致效率不佳。

    ReentrantLock

    ReentrantLock的是上层实现的乐观锁,内部维护了请求访问的线程队列,再细分为公平锁和非公平锁:

    公平锁:每次访问都需要重新排队。
    非公平锁:如果当前线程已经获得锁,再次申请直接允许,不会出现竞争。

    CountDownLatch

    乐观锁的一种,优点是可以自由控制上锁和解锁的时间。只可以使用一次:

    // 构造参数表示需要countDown2次
    final CountDownLatch latch = new CountDownLatch(2);
    // 等待countDown结束
    latch.await();
    
    // countDown调用两次,代码才会从await的位置继续运行
    latch.countDown();
    latch.countDown();
    

    CountDownLatch的使用更适合类似倒计时的场景。

    CyclicBarrier

    乐观锁的一种,与CountDownLatch不同的是:可以反复使用:

    // 构造函数表示等待的次数
    CyclicBarrier barrier = new CyclicBarrier(3);
    // 当await调用3次后,才会继续执行之后的代码
    barrier.await();
    

    CyclicBarrier的使用场景更适合类似等待的场景。

    ConcurrentHashMap

    ConcurrentHashMap的整体结构于HashMap类似,在Java 8以前采用:哈希表 + 链表的形式保存数据,采用分段锁(乐观锁,继承ReentrantLock)控制写入的并发。缺点在于节点Hash碰撞率高的时候,查找效率低下。

    在Java 8 以后采用:哈希表 + (链表/红黑树)的形式保存数据。红黑树可以提高节点Hash碰撞高时,查找数据的效率。抛弃分段锁,直接使用synchronized控制单节点并发。获取数据无加锁,所以不保证获取的数据一定是最新的。

    CopyOnWriteArrayList

    采用写入时复制的方法解决并发问题:

    数据写入时,拷贝一份当前数据,然后把新数据加入,最后把当前数据的指针指向新的数组。
    
    并发锁使用synchronized。获取数据无加锁,所以不能保证获取的数据一定是最新的。
    

    Collections工具

    如果对于数据同步的要求必须是最新的,Java提供了Collections工具类对集合直接上锁,相当于对集合的所有的方法都上锁,以下是提供了Collections提供的方法:

    synchronizedCollection
    synchronizedSet
    synchronizedNavigableMap
    synchronizedCollection
    synchronizedSet
    synchronizedNavigableSet
    synchronizedSortedSet
    synchronizedList
    synchronizedList
    synchronizedMap
    synchronizedSortedMap
    

    相关文章

      网友评论

        本文标题:常用Java线程同步工具类

        本文链接:https://www.haomeiwen.com/subject/ulosfltx.html