Java高并发之锁优化,java基础面试笔试题

中控智慧科技股份有限公司Java面试题 整个面试分为笔试和面试,过了后二面,由HR视频面试 一.笔试题 1.int num=2147483647 num+=2L; 结果是多少? 结果是:-2147483647 分析: int的范围是: 负的2的31次方=-2147483648 正的2的31次方-1=2147483647 当num+=2L的时候内存溢出+1结果变为-2147483648,再+1结果为 -2147483647 2.创建线程有... 阅读详情


我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。
扫描二维码或搜索下图红色VX号,加VX好友,拉你进【程序员面试学习交流群】免费领取。也欢迎各位一起在群里探讨技术。

 

本文主要讲并行优化的几种方式, 其结构如下:

 

锁优化

减少锁的持有时间

例如避免给整个方法加锁

 

1     public synchronized void syncMethod(){ 

2         othercode1(); 

3         mutextMethod(); 

4         othercode2(); 

5     }

 

改进后

 

1     public void syncMethod2(){ 

2         othercode1(); 

3         synchronized(this){ 

4             mutextMethod(); 

5         } 

6         othercode2(); 

7     }

 

减小锁的粒度

将大对象,拆成小对象,大大增加并行度,降低锁竞争. 如此一来偏向锁,轻量级锁成功率提高.

一个简单的例子就是jdk内置的ConcurrentHashMap与SynchronizedMap.

Collections.synchronizedMap

其本质是在读写map操作上都加了锁, 在高并发下性能一般.

ConcurrentHashMap

内部使用分区Segment来表示不同的部分, 每个分区其实就是一个小的hashtable. 各自有自己的锁.

只要多个修改发生在不同的分区, 他们就可以并发的进行. 把一个整体分成了16个Segment, 最高支持16个线程并发修改.

代码中运用了很多volatile声明共享变量, 第一时间获取修改的内容, 性能较好.

读写分离锁替代独占锁

顾名思义, 用ReadWriteLock将读写的锁分离开来, 尤其在读多写少的场合, 可以有效提升系统的并发能力.




  •  
  • 读-读不互斥:读读之间不阻塞。


     
  • 读-写互斥:读阻塞写,写也会阻塞读。


     
  • 写-写互斥:写写阻塞。


     

锁分离

在读写锁的思想上做进一步的延伸, 根据不同的功能拆分不同的锁, 进行有效的锁分离.

一个典型的示例便是LinkedBlockingQueue,在它内部, take和put操作本身是隔离的,

有若干个元素的时候, 一个在queue的头部操作, 一个在queue的尾部操作, 因此分别持有一把独立的锁.

 

 1     /** Lock held by take, poll, etc */

 2     private final ReentrantLock takeLock = new ReentrantLock();

 3 

 4     /** Wait queue for waiting takes */

 5     private final Condition notEmpty = takeLock.newCondition();

 6 

 7     /** Lock held by put, offer, etc */

 8     private final ReentrantLock putLock = new ReentrantLock();

 9 

10     /** Wait queue for waiting puts */

11     private final Condition notFull = putLock.newCondition();

 

锁粗化

通常情况下, 为了保证多线程间的有效并发, 会要求每个线程持有锁的时间尽量短,

即在使用完公共资源后, 应该立即释放锁. 只有这样, 等待在这个锁上的其他线程才能尽早的获得资源执行任务.

而凡事都有一个度, 如果对同一个锁不停的进行请求 同步和释放, 其本身也会消耗系统宝贵的资源, 反而不利于性能的优化

一个极端的例子如下, 在一个循环中不停的请求同一个锁.

 

 1     for(int i = 0; i < 1000; i++){

 2         synchronized(lock){

 3             

 4         }

 5     }

 6 

 7     // 优化后

 8     synchronized(lock){

 9         for(int i = 0;i < 1000; i++){

10             

11         }

12     }

 

锁粗化与减少锁的持有时间, 两者是截然相反的, 需要在实际应用中根据不同的场合权衡使用.

JDK中各种涉及锁优化的并发类可以看之前的博文: 并发包总结

ThreadLocal

除了控制有限资源访问外, 我们还可以增加资源来保证对象线程安全.

对于一些线程不安全的对象, 例如SimpleDateFormat, 与其加锁让100个线程来竞争获取,

不如准备100个SimpleDateFormat, 每个线程各自为营, 很快的完成format工作.

示例

 

 1 public class ThreadLocalDemo {

 2 

 3     public static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal();

 4 

 5     public static void main(String[] args){

 6         ExecutorService service = Executors.newFixedThreadPool(10);

 7         for (int i = 0; i < 100; i++) {

 8             service.submit(new Runnable() {

 9                 @Override

10                 public void run() {

11                     if (threadLocal.get() == null) {

12                         threadLocal.set(new SimpleDateFormat("yyyy-MM-dd"));

13                     }

14 

15                     System.out.println(threadLocal.get().format(new Date()));

16                 }

17             });

18         }

19     }

20 }

 

原理

对于set方法, 先获取当前线程对象, 然后getMap()获取线程的ThreadLocalMap, 并将值放入map中.

该map是线程Thread的内部变量, 其key为threadlocal, vaule为我们set进去的值.

 

1     public void set(T value) {

2         Thread t = Thread.currentThread();

3         ThreadLocalMap map = getMap(t);

4         if (map != null)

5             map.set(this, value);

6         else

7             createMap(t, value);

8     }

 

对于get方法, 自然是先拿到map, 然后从map中获取数据.

 

 1     public T get() {

 2         Thread t = Thread.currentThread();

 3         ThreadLocalMap map = getMap(t);

 4         if (map != null) {

 5             ThreadLocalMap.Entry e = map.getEntry(this);

 6             if (e != null)

 7                 return (T)e.value;

 8         }

 9         return setInitialValue();

10     }

 

内存释放




  •  
  • 手动释放: 调用threadlocal.set(null)或者threadlocal.remove()即可


     
  • 自动释放: 关闭线程池, 线程结束后, 自动释放threadlocalmap.


     

 

 1 public class StaticThreadLocalTest {

 2 

 3     private static ThreadLocal tt = new ThreadLocal();

 4     public static void main(String[] args) throws InterruptedException {

 5         ExecutorService service = Executors.newFixedThreadPool(1);

 6         for (int i = 0; i < 3; i++) {

 7             service.submit(new Runnable() {

 8                 @Override

 9                 public void run() {

10                     BigMemoryObject oo = new BigMemoryObject();

11                     tt.set(oo);

12                     // 做些其他事情

13                     // 释放方式一: 手动置null

14 //                    tt.set(null);

15                     // 释放方式二: 手动remove

16 //                    tt.remove();

17                 }

18             });

19         }

24         // 释放方式三: 关闭线程或者线程池

25         // 直接new Thread().start()的场景, 会在run结束后自动销毁线程

26 //        service.shutdown();

27 

28         while (true) {

29             Thread.sleep(24 * 3600 * 1000);

30         }

31     }

32 

33 }

34 // 构建一个大内存对象, 便于观察内存波动.

35 class BigMemoryObject{

36 

37     List<Integer> list = new ArrayList<>();

38 

39     BigMemoryObject() {

40         for (int i = 0; i < 10000000; i++) {

41             list.add(i);

42         }

43     }

44 }

 

内存泄露

内存泄露主要出现在无法关闭的线程中, 例如web容器提供的并发线程池, 线程都是复用的.

由于ThreadLocalMap生命周期和线程生命周期一样长. 对于一些被强引用持有的ThreadLocal, 如定义为static.

如果在使用结束后, 没有手动释放ThreadLocal, 由于线程会被重复使用, 那么会出现之前的线程对象残留问题,

造成内存泄露, 甚至业务逻辑紊乱.

对于没有强引用持有的ThreadLocal, 如方法内变量, 是不是就万事大吉了呢? 答案是否定的.

虽然ThreadLocalMap会在get和set等操作里删除key 为 null的对象, 但是这个方法并不是100%会执行到.

看ThreadLocalMap源码即可发现, 只有调用了getEntryAfterMiss后才会执行清除操作,

如果后续线程没满足条件或者都没执行get set操作, 那么依然存在内存残留问题.

 

 1     private ThreadLocal.ThreadLocalMap.Entry getEntry(ThreadLocal key) {

 2         int i = key.threadLocalHashCode & (table.length - 1);

 3         ThreadLocal.ThreadLocalMap.Entry e = table[i];

 4         if (e != null && e.get() == key)

 5             return e;

 6         else

 7             // 并不是一定会执行

 8             return getEntryAfterMiss(key, i, e);

 9     }

10 

11     private ThreadLocal.ThreadLocalMap.Entry getEntryAfterMiss(ThreadLocal key, int i, ThreadLocal.ThreadLocalMap.Entry e) {

12         ThreadLocal.ThreadLocalMap.Entry[] tab = table;

13         int len = tab.length;

14 

15         while (e != null) {

16             ThreadLocal k = e.get();

17             if (k == key)

18                 return e;

19             // 删除key为null的value

20             if (k == null)

21                 expungeStaleEntry(i);

22             else

23                 i = nextIndex(i, len);

24             e = tab[i];

25         }

26         return null;

27     }

 

最佳实践

不管threadlocal是static还是非static的, 都要像加锁解锁一样, 每次用完后, 手动清理, 释放对象.

无锁

与锁相比, 使用CAS操作, 由于其非阻塞性, 因此不存在死锁问题, 同时线程之间的相互影响,

也远小于锁的方式. 使用无锁的方案, 可以减少锁竞争以及线程频繁调度带来的系统开销.

 

例如生产消费者模型中, 可以使用BlockingQueue来作为内存缓冲区, 但他是基于锁和阻塞实现的线程同步.

 

如果想要在高并发场合下获取更好的性能, 则可以使用基于CAS的ConcurrentLinkedQueue.

 

同理, 如果可以使用CAS方式实现整个生产消费者模型, 那么也将获得可观的性能提升, 如Disruptor框架.


 

关于无锁, 这边不再赘述, 之前博文已经有所介绍, 具体见: Java高并发之无锁与Atomic源码分析

 


转载:https://www.cnblogs.com/xdecode/p/9137804.html

推荐内容:
两道面试题,带你解析Java类加载机制
Java的深拷贝和浅拷贝
面试题思考:什么是 Java 的反射机制
Java面试题——中级(下)
java开发常用技术
java 协程
Java精选面试题之Spring Boot 三十三问
推荐几个IDEA插件,Java开发者撸码利器。
Java面试题收集
Java集合必会14问(精选面试题整理)

 

最新Java笔试题及答案,java高分面试指南 单个redis节点的并发能力是有限的,所以为了提高并发能力,我们需要搭建redis集群,就比如:主从复制。主从复制的流程主从复制主要分为:全量同步和增量同步。全量同步:在salve请求数据同步的时候会携带application Id和offset,如果master判断出applid和自己的不一样,就认为slave是第一次进行同步,所以会进行全量同步。 阅读详情

相关推荐

Java面试篇基础部分- 锁详解

偏向锁的主要目的是在同一个线程多次获取某个锁的情况下尽量减少轻量级锁的执行路径,因为在轻量级锁中,需要多次的执行CAS的操作。在多线程执行过程中,同时被阻塞,他们之间等待相互之间释放锁,如果都不能释放锁就会出现死锁,为了避免出现死锁,可以对锁进行一个加超时时间的操作,或者是在适当的代码中对锁进行释放。在实际中,除了多线程之间存在竞争锁的情况,还会出现同一个锁被同一个线程多次获取的情况,偏向锁就是用于在某个线程获取某个锁之后,消除这个锁重入的开销。锁升级:无锁、偏向锁、轻量级锁、重量级锁。

初学者 2228

Java高并发之锁优化

本文主要讲并行优化的几种方式, 其结构如下: 锁优化 减少锁的持有时间 例如避免给整个方法加锁 1 public synchronized void syncMethod(){ 2 othercode1(); 3 mutextMethod(); 4 othercode2(); 5 } 改进后 ...

weixin_30882895的博客 252

java并发锁面试知识

java中的乐观锁与悲观锁,synchronized与ReentrantLock重入锁的说明与比较

java 关于锁常见面试题

我个人认为,如果你想靠着背面试题来获得心仪的offer,用癞蛤蟆想吃天鹅肉形容完全不过分。想必大家能感受到面试越来越难,想找到心仪的工作也是越来越难,高薪工作羡慕不来,却又对自己目前的薪资不太满意,工作几年甚至连一个应届生的薪资都比不上,终究是错付了,错付了自己没有去提升技术。这些面试题分享给大家的目的,其实是希望大家通过大厂面试题分析自己的技术栈,给自己梳理一个更加明确的学习方向,当你准备好去面试大厂,你心里有底,大概知道面试官会问多广,多深,避免面试的时候一问三不知。

m0_72758098的博客 767

point transformer v3结构

分割结构: embedding->enc->dec embedding->enc0->enc1->enc2->enc3->enc4->dec3->dec2->dec1->dec0 embedding ->block0->block1 ->dow->block0->block1 ->dow->block0->block1 ->dow->block0->block1-&gt

weixin_45625419的博客 581

ClickHouse集群扩容实战:用clickhouse-copier搞定数据迁移与分片重平衡

本文详细介绍了使用clickhouse-copier工具实现ClickHouse集群从3分片到5分片的平滑扩容实战。通过分片级并行处理、原子性保证等核心机制,该工具能高效完成数据迁移与分片重平衡,同时保持服务连续性。文章涵盖集群拓扑规划、表结构检查、迁移配置、执行监控及迁移后优化等关键步骤,为大数据量场景下的ClickHouse扩容提供完整解决方案。

weixin_29091837的博客 290

面试题——Java中的锁

文章目录1、synchronized 关键字是怎么用的?1.1 构造方法可以使用 synchronized 关键字修饰么?1.2 使用 String 作为锁对象,会有什么问题?1.3 synchronized 的底层原理有了解吗?1.4 还使用过其他锁吗?2、volatile 有什么作用?2.1 原理是什么?2.2 和 synchronized 有什么区别?3. 写一个单例模式 1、synchronized 关键字是怎么用的? synchronized 关键字解决的是多个线程之间访问资源的同步性,sync

Q_P777的博客 3364

Win10/Win11系统下冒险岛V128单机版一键搭建教程(含MySQL配置避坑指南)

本文提供Win10/Win11系统下冒险岛V128单机版一键搭建的详细教程,涵盖服务端部署、MySQL配置优化及常见问题解决方案。通过本指南,玩家可轻松实现单机版冒险岛的一键启动,重温经典游戏体验,同时避免常见的技术陷阱。

weixin_29261711的博客 646

Java高并发锁优化策略详解

在当今的软件开发领域,高并发已经成为一个不可忽视的关键问题。尤其是在Java这种广泛应用于企业级应用的语言中,如何有效地处理并发成为了一个重要的课题。在这个背景下,锁优化成为了Java并发编程中的一个核心知识点。想象一下,在一个多线程环境中,多个线程同时访问共享资源时,如果没有适当的锁机制,很容易导致数据不一致或者程序崩溃。因此,理解锁的定义、类型和特性对于确保程序的正确性和性能至关重要。锁是Java并发编程中用于控制对共享资源访问的一种机制。

我是Java程序员廖志伟,感谢朋友们的支持! 1186

unity转微信小游戏:UI大小设置

unity转微信小游戏:UI大小设置

会潜水的小火龙的博客 3266

UNet改进(54):当医学图像分割遇上频域学习与自监督

本文提出了一种改进U-Net的方法,通过频域增强模块和代理任务模块提升医学图像分割性能。频域增强模块在傅里叶空间对特征图进行可学习的频率调制,重点增强高频细节特征;代理任务模块通过图像重建约束编码器保留关键信息。两个模块协同工作,在仅增加5%参数量的情况下,形成空间域、频域和重建约束三条互补的信息路径。该方法特别适用于需要精细边缘分割的医学图像任务,预期能提升5%-10%的边缘分割精度,在小样本场景效果更显著。部署时可移除代理任务模块,不影响推理效率。未来可探索空间自适应频域调制和更丰富的代理任务设计。

2501_91516851的博客 224

JAVA基础面试题:Java中的锁优化技术与偏向锁(Biased Locking)在高并发场景下的性能分析

面试官:今天的讨论非常深入,尤其是你对偏向锁的性能分析和适用场景的总结非常到位。Victor锁优化是Java并发编程的核心话题,很高兴能有机会和大家一起探讨。(文章总字数:约8000字)

Victor_119的博客 845

Vue - 解决 Property or method “__v_isRef“ is not defined on the instance but referenced(浏览器控制台报错,代码没错)

vue,vue2控制台报错,vue报错Propertyormethod"__v_isRef"isnotdefinedontheinstancebutreferenced,vue代码没问题,但是报错Propertyormethod"__v_isRef"isnotdefinedontheinstancebutreferenced,vue2如何解决报错,vue怎么解决报错问题,vue2Propertyormethod"__v_isRef"isnotdefi

🏆 前端领域优质创作者 4499

Java高并发:锁粗化优化策略

在多线程编程中,尤其是在高并发场景下,线程间的同步操作是保证数据一致性和系统稳定性的关键。然而,过多的细粒度锁操作会导致线程频繁切换,降低系统性能。为了解决这个问题,引入了锁粗化的概念。以下是一个与锁粗化相关的场景问题:在一个高并发系统中,多个线程需要访问同一份数据进行修改。如果每个线程都对数据中的单个字段进行加锁和解锁操作,那么锁的粒度就非常细。这种情况下,线程在等待锁释放的过程中可能会发生大量的上下文切换,导致系统响应时间延长,性能下降。为什么需要介绍锁粗化这个知识点呢?

MoneyHacksPro的博客 862

国科大作业考试资料-人工智能原理与算法-2024新编-第十一次作业整理

1、有一位教授想知道学生是否睡眠充足。每天,教授观察学生在课堂 上是否睡觉,并观察他们是否有红眼。教授获得如下的领域知识: (1)没有观察数据时,学生睡眠充足的先验概率为0.7。 (2)给定学生前一天睡眠充足为条件,学生在晚上睡眠充足的概率是0.8;如果前一天睡眠不充足,则是0.3。 (3)如果学生睡眠充足,则红眼的概率是0.2,否则是0.7。 (4)如果学生睡眠充足,则在课堂上睡觉的概率是0.1,否则是0.3。 将这些信息形式化为一个动态贝叶斯网络,使教授可以使用这个网络从观察序列中进行滤波和预

MatsumotoChrikk 1055

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java 多线程(八)—— 锁策略,synchronized 的优化,JVM 与编译器的锁优化,ReentrantLock,CAS

介绍Java 多线程的锁策略,synchronized 的优化,JVM 与编译器的锁优化,ReentrantLock,CAS

熵减玩家 1万+

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Java面试高频知识点:OOM、JVM、锁升级、高并发、事务如何备考?

Java面试高频知识点:OOM、JVM、锁升级、高并发、事务如何备考? 1. 引言:备考 Java 面试的核心领域 Java 面试中 JVM 和 OOM 是关键环节,高并发和事务更是热门考点!如何全面备考? 在这篇文章中,猫头虎将帮助你重点掌握: OOM 异常类型与排查方法 🚀 JVM 的内存模型与调优技巧 锁的升级机制与高并发场景优化 事务的隔离级别与典型应用场景 用理论+实战的方式,全面备考 Java 面试!

猫头虎技术团队:授渔优于赠鱼,兴趣引领智慧,探索之乐尤显珍贵。商务合作+:Libin9iOak ,万粉变现+:优快云WF,猫头虎承诺每年免费为100名C站创作者做账号流量诊断服务!全网搜:猫头虎技术团队,点击文章底部名片或直接私信我一切皆可谈,快找虎哥! 2566

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

JAVA基础面试题:Java中的偏向锁(Biased Locking)与轻量级锁的性能优化机制及其在高并发场景下的应用

本次面试围绕Java中的偏向锁和轻量级锁展开了深入讨论,涵盖了它们的工作原理、适用场景、优缺点以及设计思想。通过这些技术点的分析,可以更好地理解JVM在高并发场景下的性能优化机制。

qq_61302385的博客 916

JAVA基础面试题:深入解析Java中的偏向锁(Biased Locking)与轻量级锁的性能优化机制及其在高并发场景下的应用

面试官:最后,能否总结一下偏向锁和轻量级锁的核心价值?Victor:偏向锁和轻量级锁的核心价值在于减少无竞争或低竞争场景下的同步开销。它们通过避免线程阻塞和减少CAS操作,显著提升了单线程或低并发场景的性能。然而,在高竞争场景下,锁膨胀为重量级锁是必要的,以保证线程安全。面试官Victor。

qq_61302385的博客 650

面试加分项:精通Java高并发下的锁优化策略

在多线程程序中,同步机制是用来控制不同线程间执行顺序的机制,它帮助我们解决并发执行时可能会出现的竞争条件问题。Java提供了多种同步机制,包括synchronized关键字、锁(Locks)、信号量(Semaphores)、倒计数器(CountDownLatch)等,来帮助程序员解决线程安全问题。

逆流的小鱼 1112
上一篇: 漫谈Java IO之基础篇,java初级面试笔试题
下一篇: JAVA 与 sqlite3 连接,java开发面试笔试题
ccc_ccc8
博客等级 码龄8年 8粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值