精选面试题

并发编程

一.Executor

为什么使用线程池:手动创建线程耗费性能,不利于管理。

首先创建线程池有两种方式:使用Executors工厂来创建ThreadPoolExecutor这类自定义线程池。

1. 使用Executors工厂来创建

Executors是一个类,用来创建线程池,常用的有四种线程池

1.newFixedThreadPool 创建一个可重复固定的线程数的线程池

2.newCachedThreadPool 创建一个可缓存的线程池,调用execute将重复用以前构造的线程(如果当前线程可用)。如果没有可用线程则创建新的线程并加入到池中。终止并从缓存中移除那些已有60s未被使用的线程。

3.newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

4. newScheduledThreadPool 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

使用示例:

2. 使用ThreadPoolExecutor这个类自定义创建线程池

.ThreadLocal

https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/6782674c-1bfe-4879-af39-e9d722a95d39.png

.Volatile关键字的理解

两层语义:

1.保证不同线程对该变量的内存可见线

2.禁止进行指令重排序

内存语义:

读这个变量的时候,JMM会把本地内存中的变量设置为无效,从主内存中取;

写这个变量的时候,JMM会把本地内存变量刷新到主内存当中

实现:添加Volatile关键字会在汇编代码中多处一个kock前指令,也就是内存屏障

.Synchronized关键字

(1)synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

    1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;

    2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

    3. 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;

    4. 修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象

(2)Synchronized的作用主要有三个:(1)确保线程互斥的访问同步代码(2)保证共享变量的修改能够及时可见(3)有效解决重排序问题。

(3)Synchronized 原理

    在编译的字节码中加入了两条指令来进行代码的同步。

    monitorenter :

    每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

    1.如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。

    2.如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.

    3.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

 monitorexit:

    执行monitorexit的线程必须是objectref所对应的monitor的所有者。

    指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。
通过这两段描述,我们应该能很清楚的看出Synchronized的实现原理,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

(4)Synchronized的优化

(4)synchronized与Lock的区别

    lock是一个类,主要有以下几个方法:

    lock():获取锁,如果锁被暂用则一直等待

    unlock():释放锁

    tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true

    tryLock(long time, TimeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间

https://note.youdao.com/yws/public/resource/cc25598bbaff18a55569c256de4cf1c6/xmlnote/10A95AB8238442569108FC93755C91FF/1701

  (1)Lock的加锁和解锁都是由java代码实现的,而synchronize的加锁和解锁的过程是由JVM管理的。

 (2)synchronized能锁住类、方法和代码块,而Lock是块范围内的。

(3)Lock能提高多个线程读操作的效率;

(4)Lock:Lock实现和synchronized不一样,后者是一种悲观锁,它胆子很小,它很怕有人和它抢吃的,所以它每次吃东西前都把自己关起来。而Lock底层其实是CAS乐观锁的体现,它无所谓,别人抢了它吃的,它重新去拿吃的就好啦,所以它很乐观。如果面试问起,你就说底层主要靠volatile和CAS操作实现的。
.CAS机制

Compare And Swap

CAS操作是一个原子操作,由一条CPU指令完成,使用了3个基本操作数,内存地址V,旧的预期值A ,要修改的新值B

需要更新一个变量的时候,只有当内存地址V中的值和预期值A相等的时候才会修改为新值B ,如果失败则自旋,重新尝试

问题:

1.ABA 解决办法,加一个版本号,只有当版本号和预期值都符合的时候才修改

2.不能保证代码块的原子性,CAS机制知识保证一个变量的原子操作

.JMM的理解


JMM的核心是找到一个平衡点,在保证内存可见性的前提下,尽量的放松对编译器和处理器重排序的限制。

可能会产生缓存一致性的问题:

1.总线锁定

2.缓存一致性协议

三大特性:原子性,可见性,有序性

.JVM的锁优化

1.自旋锁和自适应自旋锁

线程挂起和恢复都需要很大的性能开销,很多共享数据的锁定状态只持续很短的时间,为这段时间挂起恢复不值得,所以可以让现场进入一个自旋状态,但仍占用cpu的时间,默认是10次,超过10次则采用传统的方式挂起线程。自适应自旋锁会根据上次在这个锁上自旋的时间调整自选次数

2.锁消除

检测到对局部变量加锁,会自动将锁消除,如在一个方法里面有sb = s1 + s2 + s3以前会转化为StringBuffer(线程安全,有加锁)的append操作,优化之后会转换成StringBuilder的sppend操作

3.锁粗化

对一个对象反复加锁解锁,如上述的append方法,编译器会优化,只在最外层加一个锁

4.轻量级锁

对象有一个对象头,对象头分两部分区域,一部分存储子树的hashcode,GC分代年龄,锁标志位等,官方成为mark word,另一部分用于存储指向方法区对象类型的指针;

轻量级锁的执行过程是代码进入同步块的时候,如果当前对象没有被锁定(锁标志为是01)则先在线程的栈帧中建立一个锁记录空间(lock record)将对象的mark word拷贝过来,然后利用cas操作尝试将对象的markword更新为指向lock record,如果成功则当前线程拥有该对象锁,并且将锁标志位从01改为00,如果更新失败则会检查当前对象markword是否指向当前线程的栈帧,如果是则直接进入同步块执行否则说明当前的对象锁已经被其他线程占有。如果有两条以上的线程竞争这个锁,那就会膨胀成重量级锁,锁标志为变成10;

5.偏向锁

锁对象第一次被线程获取的时候,会将当前的锁标志设置为偏向锁01状态,并使用cas操作将当前线程的id记录在markword当中,如果成功那么在以后的操作当中不需进行任何操作就可以进入同步代码块,当有另外一个线程获取当前锁的时候,偏向模式就宣告结束,撤销偏向锁之后恢复到未锁定或者轻量级锁状态

七:Java异常体系

http://assets.tianmaying.com/md-image/c887bccaa4b144622c82685097908f3d.png
 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值