文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java多线程的同步优化的6种方案

2024-04-02 19:55

关注

概述

处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。

加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。

在Java内存模型中,分为主内存和线程工作内存,线程使用共享数据时,先从主内存中拷贝数据到工作内存,使用完成之后再写入主内存中。

在Java中,有多线程并发时,我们可以使用多线程同步的方式来解决内存一致性的问题。通常我们可以在程序中添加同步锁来保障数据的安全访问,但是也经常会带来一些同步性能问题,那么本章将针对常见的同步问题给出了一些优化方案。

读写锁

在多线程操作下,如果我们的某些数据经常被读取操作,但非常少的时机被写入操作。这时,如果我们使用synchronized等同步方式,性能会非常低。

这种场景下,我们应该使用读写锁来进行优化。

读写锁的特点:

某些特定的场景,使用读写锁会极大的提高多线程并发操作的效率。因为,读写锁中,读锁不是排它锁,所以可以并发执行,可以非常显著的提高读取效率;只有在写锁时,是排它锁,这时需要等待写锁的释放。

ReetrantReadWriteLock

ReadWriteLock接口

Java并发包中ReadWriteLock是一个接口,抽象了读写锁方法:


public interface ReadWriteLock {
    
    Lock readLock();

    
    Lock writeLock();
}

ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。

ReetrantReadWriteLock类

Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性。

1. ReetrantReadWriteLock获取锁顺序有两种模式:

2. 可重入

ReetrantReadWriteLock锁是可重入的,当然一个线程获取多少次锁,就必须释放多少次锁。

3. 锁降级

在读写锁中,锁降级:从写锁变成读锁;锁升级:从读锁变成写锁。

读写锁状态的设计

读写锁的状态是用一个int值来表示的。state(int32位)字段分成高16位与低16位,其中高16位表示读锁个数,低16位表示写锁个数。

例如,当前一个线程获取到了写锁,并且重入了两次,因此低16位是3,并且该线程又获取了读锁,并且重入了一次,所以高16位是2,当写锁被获取时如果读锁不为0那么读锁一定是获取写锁的这个线程。

写时复制

写时复制(Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者同时要求相同资源,他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的。此作法主要的优点是如果调用者没有修改该资源,就不会有副本被创建,因此多个调用者只是读取操作时可以共享同一份资源。

在Java中,Copy on Write这种机制通常用在集合上,在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改。修改完成之后,将指向原来容器的引用指向新的容器(副本容器)。

写时复制的特点

Java写时复制容器类

JDK中提供了CopyOnWriteArrayList类和CopyOnWriteArraySet类,实现了写时复制。

减小锁的粒度

如果我们在一个大的数据操作类里面,大量使用了锁,并且还是同一个锁,这时,我们的多线程同步效率就会变得非常低。

我们可以将数据按照不同的类型及应用场景进行分割,然后用不同的锁进行同步,这样,不同的场景下就不会产生排它锁的冲突问题,可以大大提高同步的效率。

该方案简单来说就是将一个大锁,分割成多个小锁,这样就能显著的提高多线程并发执行的效率。

减小锁的占有时间

如果在一个较大的方法中,我们直接给该方法加了一个锁,但是我们需要同步的地方只是该方法中的一行操作代码,这样就是很糟糕的同步使用方式了。

我们可以将锁细化到使用它的代码行上,而不是整个函数都加锁,这样锁的持有时间就会变少,从而提高了多线程同步的性能。

该方案是将同步块的代码范围减小,从而降低锁的持有时间,达到优化多线程同步性能的目的。

锁粗化

虽然说,减少锁的占有时间可以提高性能,但是有时候,这种方式并不适用。

例如,一个循环中,我们在循环体中,使用了锁,这样反而会降低性能,这时我们应该在循环开始之前加锁,结束之后释放,也就是将锁粗化。

这是为什么呢?

这是因为,频繁的对锁进行请求、释放、状态修改等操作,会造成大量系统资源的消耗,从而降低性能。

ThreadLocal

同步效率低,是因为多线程同步等待造成的,那么我们可以换一个思路,如果让每个线程都持有一份数据,那这样就不会存在竞争的问题了,也就不需要同步锁了。这样就会很大程度上提高多线程并发的性能。

关于ThreadLocal相关实现原理及使用可以参考之前的文章《ThreadLocal线程本地对象原理分析》。

总结

Java中可以使用锁来解决多线程的同步问题,保障了数据的一致性,但也会代理很多问题,本章总结了多线程同步的几种优化方案:

到此这篇关于Java多线程的同步优化的6种方案的文章就介绍到这了,更多相关Java多线程同步优化内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯