面试现场【多线程篇】

  Java   5分钟   629浏览   0评论

面试官看你简历上写了精通多线程,来聊聊,为什么要使用多线程呢?

小邹:使用多线程最主要的原因是提高系统的资源利用率。

小邹:多个线程同时运行,可以减少线程上下文切换的开销,提高并发的能力和CPU的利用效率。

小邹:在平时工作中多线程也是常见的。比如Tomcat每处理一个请求都会从线程连接池里取一个线程去处理。

面试官嗯,那什么场景可以使用多线程呢?

小邹:一些并发量大的场景,比如读入大量文件写入数据库,使用多线程能够极大提高效率。

小邹:耗时比较长的任务,比如用户注册之后发送邮件、短信之类的操作,这种任务就算失败了也不是特别重要,可以使用异步线程去处理。

小邹:定时任务,比如定期更新配置文件、备份数据之类的任务。

面试官嗯,平时在使用多线程的时候,可能会遇到线程安全的问题吧。讲讲什么是线程安全?

小邹:我是这么理解的,当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。

面试官那你平时怎么处理线程安全问题的?

小邹:这个还得具体问题具体分析。首先判断有没有线程安全问题,若有则根据具体的情况去处理线程安全的问题。

小邹:比如涉及到操作的原子性,可以考虑使用原子类。

小邹:如果涉及到对线程的控制,可以考虑线程工具类CountDownLatch/Semaphore等等。

小邹:集合类的话,考虑java.util.concurrent包下的集合类。

小邹:还有synchronizedlock包下的类,redis分布式锁等。

面试官:刚刚提到synchronized,讲讲它的底层原理?

小邹synchronized 同步代码块的实现是通过 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。当执行 monitorenter 指令时,线程试图获取锁也就是获取 monitor 的持有权。(monitor对象存在于每个Java对象的对象头中,synchronized锁便是通过这种方式获取锁的,这也是为什么Java中任意对象可以作为锁的原因。)

小邹:其内部包含一个计数器,当计数器为0则可以成功获取,获取后将锁计数器设为1也就是加1。相应的在 执行 monitorexit 指令后,将锁计数器设为0 ,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。

小邹synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是ACC_SYNCHRONIZED标识,该标识指明了该方法是一个同步方法,JVM 通过该 ACC_SYNCHRONIZED 访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。

面试官:那synchronized和ReentrantLock有什么区别呢?

小邹

  1. 使用synchronized关键字实现同步,线程执行完同步代码块会自动释放锁,而ReentrantLock需要手动释放锁。
  2. synchronized是非公平锁,ReentrantLock默认是非公平锁,可以设置为公平锁。
  3. ReentrantLock上等待获取锁的线程是可中断的,线程可以放弃等待锁。而synchonized会无限期等待下去。
  4. ReentrantLock 可以设置超时获取锁。在指定的截止时间之前获取锁,如果截止时间到了还没有获取到锁,则返回。
  5. ReentrantLock 的 tryLock() 方法可以尝试非阻塞的获取锁,调用该方法后立刻返回,如果能够获取则返回true,否则返回false。

面试官:什么叫公平锁和非公平锁?

小邹:如果是按照线程访问顺序去获取对象锁,则为公平锁,否则为非公平锁。

面试官:知道什么是CAS吗?

小邹:嗯,CAS全称Compare And Swap,比较与交换,是乐观锁的主要实现方式。CAS 在不使用锁的情况下实现多线程之间的变量同步。ReentrantLock 内部的 AQS 和原子类内部都使用了 CAS。

小邹:CAS算法涉及到三个操作数:需要读写的内存值 V;进行比较的值 A;要写入的新值 B。

小邹:只有当 V 的值等于 A 时,才会使用原子方式用新值B来更新V的值,否则会继续重试直到成功更新值。

小邹:以 AtomicInteger 为例,AtomicInteger 的 getAndIncrement()方法底层就是CAS实现,关键代码是 compareAndSwapInt(obj, offset, expect, update),其含义就是,如果obj内的valueexpect相等,就证明没有其他线程改变过这个变量,那么就更新它为update,如果不相等,那就会继续重试直到成功更新值。

面试官:基础掌握的不错,今天面试就到这吧~

如果你觉得文章对你有帮助,那就请作者喝杯咖啡吧☕
微信
支付宝
  0 条评论