Java并发编程—常见面试题

建议:

  • 学习java并发前需要先掌握JVM知识
  • 关于下面问题档案的详细解析都在后面推荐的相关系列文章中

 

一、线程安全相关

1、什么叫线程安全?

线程安全就是说多线程访问同一代码,不会产生不确定的结果

2、为什么会存在线程安全的问题?

  • 共享性:多个线程操作同一个类实例时,类属性是共享的。
  • 互斥性:为保证数据安全性,同一时刻只有一个线程可以修改数据

3、如何保证线程安全?

  • 原子性:针对代码块
  • 可见性:数据从线程工作内存刷新到JVM主存中这个动作必须是同步的
  • 有序性:指令重排,操作系统对指令进行重排序时只保证单线程时最终结果的正确性,不能保证多线程情况下最终结果的正确性

4、同步有几种实现方法?(或者问Java 程序中怎么保证多线程的运行安全?) 

JDK内置的syncchronized关键字、共享变量(volatile)实现线程同步、JUC的可重入锁ReentrantLock类、使用局部变量实现线程同步

5、volatile关键字有什么作用?弊端是什么?适用场景是什么?

1)作用:通过volatile关键字可以保证变量的可见性和有序性,但不能保证原子性

  • 可见性:变量修改被立即刷新到主存中;变量读取不能从工作内存读取,必须从主存读取。(通过硬件锁保证线程安全的)
  • 有序性:volatile变量前的代码不能重排到volatile变量后,volatile变量后的代码也不能重排到volatile变量前。

2)弊端

  • 原子性:i++操作是非线程安全的,即使通过volatile关键字修饰也不能保证其原子性

3)适用场景

6、volatile与synchronized区别是什么?什么场景下可以使用volatile替换synchronized?

volatile只能保证可见性和有序性,synchronized可以保证原子性、可见性、有序性

  • 状态标志:把简单地volatile变量作为状态标志,来达成线程之间通讯的目的,省去了用synchronized还要wait、notify或者interrupt的编码麻烦。
  • 替换重量级锁:如果某个变量仅是单次读或者单次写操作,没有复合操作(i++,先检查后判断之类的)就可以用volatile替换synchronized

二、CAS相关

1、CAS是什么

CAS是乐观锁思想的一种实现方式,也是无锁保证变量线程安全的一种方式。原理是将变量的新值写入主存前,需要比较工作内存中的旧值和主存中的旧值是否相等(相等说明主存中的变量没有被其他线程修改过),相等则将新值写入主存中。

2、ABA问题

比如说一个线程one从内存位置V取出value_A,这时候另一个线程two也从内存中取出value_A,并且线程two进行了一些操作变成了value_B,然后two又将V位置的数据变成value_A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。解决方法:通过版本号(version)的方式来解决,每次比较要比较数据的值和版本号两项内容即可。

3、atomic 的原理?

 

三、锁的种类

1、分类

  • 乐观锁/悲观锁:假设每次操作都不会冲突,若是遇到冲突失败就重试直到成功;悲观锁是让其他线程都等待,等锁释放完了再竞争锁。
  • 共享锁/独占锁:也叫读写锁/互斥锁
  • 公平锁/非公平锁
  • 可重入锁:线程可以进入任何一个它持有锁的线程
  • 自旋锁
  • 自适应自旋锁
  • 无锁/偏向锁/轻量级锁/重量级锁

2、乐观锁/悲观锁实现方式?

  • 乐观锁实现方式:cas,volatile
  • 悲观锁实现方式:synchronized,Lock

3、读写锁可以用于什么场景?

适用于少写多读的情况,互斥锁效率低,而多线程都是读的情况不需要互斥,只有读-写、写-写冲突时才需要互斥,通过读写锁可以提高效率,具体工具类是ReentrantReadWriteLock

4、什么时候应该使用可重入锁?

可重入锁指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,ReentrantLock 和synchronized都是可重入锁,所以大部分情况下使用的都是可重入锁

5、锁的4种状态以及膨胀过程

膨胀方向:无锁 → 偏向锁 → 轻量级锁 → 重量级锁(只能单向膨胀,不能逆膨胀)

膨胀原因:多线程竞争加剧,导致锁升级

6、什么是死锁? 怎么防止死锁?

 

三、Synchoronied

1、Synchoronied是什么?

关键词:重量级锁、悲观锁、互斥锁、

2、使用方法

用于修饰普通函数、静态函数、代码块

3、底层原理:

通过底层cpu的monitorenter和monitorexit对线程的出入进行控制

4、优化:

轻量级锁、偏向锁

5、当一个线程进入某个对象的一个synchronized的实例方法后,其它线程是否可进入此对象的其它方法?

  • 如果其他方法前加了synchronized关键字,就不能,如果没加synchronized,则能够进去。因为一个对象只有一个monitor锁,当一个线程进入synchronized的实例方法后便获得了当前对象的monitor锁,其他线程由于无法获得monitor锁,所以无法进入此对象的其它被synchronized修饰的方法。
  • 如果这个方法内部调用了wait(),则释放了monitor锁,则可以进入其他加synchronized的方法。如果其他方法加了synchronized关键字,并且没有调用wai方法,则不能。

四、Lock类

1、底层原理:

依赖于AQS

2、AQS原理?

关键词:juc包的Lock类的基石

数据结构:带有头尾指针的双向链表,节点Node中包含头指针、尾指针、抢占状态3个重要的属性

作用:实现线程的抢锁、释放锁、排队等待、阻塞唤醒等操作

3、Lock锁、ReentrantLock、ReentrantWriteReadLock、LockSupport?

 

4、CountDownLatch、CyclicBarrier 、Semaphore?

 

5、wait/notify()/notifyAll()、await()/signal/signalAll区别?

 

6、synchronized和java.util.concurrent.locks.Lock的异同?

  • 主要相同点:Lock能完成Synchronized所实现的所有功能。
  • 主要不同点:

 

五、多线程操作相关

1、并行和并发有什么区别?

2、线程和进程的区别?

3、 守护线程是什么?

4、创建线程有哪几种方式?

5、说一下 runnable 和 callable 有什么区别?

6、线程有哪些状态?

7、 sleep() 和 wait() 有什么区别?

8、notify()和 notifyAll()有什么区别?

9、 线程的 run() 和 start() 有什么区别?

10、创建线程池有哪几种方式?

11、线程池都有哪些状态?

12、线程池中 submit() 和 execute() 方法有什么区别?

13. ThreadLocal 是什么?有哪些使用场景?

六、并发编程实战

1、如何实现一个流控程序,用于控制请求的调用次数?

 

答案参考:Java并发编程—实战

 

Java并发编程系列文章:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值