Java面试题07

news2024/11/24 9:33:17

1.线程池都有哪些状态?

        线程池的状态有RUNNING(运行中)、SHUTDOWN(关闭中,不接受新任务)、 STOP(立即关闭,中断正在执行任务的线程)和TERMINATED(终止)。

1、RUNNING

(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。 
(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!

2、 SHUTDOWN

(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。 
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

3、STOP

(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。 
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4、TIDYING

(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。 
(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。 
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5、 TERMINATED

(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。 
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

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

        submit()方法可以提交Callable任务,并返回Future对象;execute()方法只能提交 Runnable任务,无返回值。

  submit()execute()方法都是用于在线程池中提交任务的方法,但它们之间的主要区别在于任务的返回值和异常处理。

execute()方法是用于提交不需要返回值的任务。它接收一个Runnable对象作为参数,然后在线程池中执行这个Runnable对象。execute()方法没有返回值,因此不能用来获取任务的结果。如果任务执行过程中出现异常,execute()方法会直接抛出这个异常,而不会返回任何错误信息。

submit()方法则可以用于提交需要返回值的任务。它接收一个Callable对象作为参数,然后在线程池中执行这个Callable对象。submit()方法返回一个Future对象,可以通过这个Future对象来获取任务的结果。如果任务执行过程中出现异常,Future对象会保存这个异常,在获取任务结果时抛出。

总结一下,如果你需要获取任务的结果,那么应该使用submit()方法;如果你不需要获取任务的结果,或者你不需要等待任务执行完成,那么可以使用execute()方法。

3.在 java 程序中怎么保证多线程的运行安全?

        可以使用synchronized关键字、Lock接口、原子类等机制,确保多个线程访问共享资源时 不会出现数据竞争。

        

在Java程序中,有多种方法可以保证多线程的运行安全。以下是一些主要的策略:

  1. 同步(Synchronization): Java的synchronized关键字可以保证同一时间只有一个线程可以执行某个方法或者某个代码块,这样就可以避免多个线程同时修改同一个数据而引发的不一致问题。
  2. 使用volatile关键字volatile关键字可以保证变量的修改对所有线程可见,避免了线程之间的数据不一致问题。
  3. 使用Atomic:Java的java.util.concurrent.atomic包提供了一些原子操作类,如AtomicIntegerAtomicLong等,这些类可以保证对基本数据类型的操作是原子的。
  4. 使用线程安全的数据结构:Java提供了一些线程安全的数据结构,如VectorHashtable等,这些数据结构内部已经实现了同步,可以保证在多线程环境下的安全。
  5. 使用并发包(java.util.concurrent):Java的并发包提供了一些高级的并发工具,如SemaphoreCountDownLatchCyclicBarrier等,这些工具可以帮助你更好地控制线程的执行流程,避免多个线程同时访问共享资源的问题。
  6. 避免共享状态:尽可能地设计出无状态的程序,或者将状态信息局部化,可以减少线程间的竞争。如果必须共享状态,那么应该使用上述提到的方法来保证线程安全。
  7. 使用高级的并发类:Java 5以后,提供了一些更高级的并发类,如ThreadPoolExecutorScheduledThreadPoolExecutor等,它们可以更灵活地控制线程池的大小和任务的执行。
  8. 避免死锁:死锁是多线程编程中常见的问题,可以通过避免循环等待,按顺序获取锁,或者使用Java的ReentrantLock等机制来避免。

以上这些方法都可以在一定程度上保证多线程的运行安全,但需要注意的是,没有一种方法可以解决所有的并发问题。在实际编程中,需要根据具体的问题和场景来选择合适的方法。

        4.多线程锁的升级原理是什么?

在JVM中,锁会根据竞争情况从无锁升级为偏向锁、轻量级锁,最终升级为重量级锁,以适 应不同场景的线程竞争。

多线程锁的升级原理主要是指在Java中,当一个线程需要访问共享数据时,会先尝试获取锁,如果成功,则进入临界区执行操作;如果失败,则说明存在竞争,需要进行锁升级。

具体的锁升级过程如下:

  1. 在偏向锁状态下,对象头中的Mark Word被设置为偏向锁标记,并记录了持有锁的线程ID。因此,当一个线程访问共享数据时,无需进行同步操作,可以直接进入临界区执行操作。如果其他线程也需要访问该共享数据,此时需要升级为轻量级锁状态。
  2. 在轻量级锁状态下,对象头中的Mark Word被设置为指向锁记录的指针,同时锁记录结构体中包含了持有锁的线程ID和锁标志位等信息。此时,竞争线程会使用CAS(Compare and Swap)操作尝试获取锁,如果成功获取锁,则直接进入临界区执行操作;如果获取失败,则说明存在竞争,需要升级为重量级锁状态。
  3. 在重量级锁状态下,对象头中的Mark Word被设置为重量级锁标记,并将当前线程挂起,等待锁被释放后再唤醒线程进行竞争。由于重量级锁采用了操作系统内核的互斥机制,因此会引入较大的性能开销。

5.什么是死锁?

死锁是指两个或多个线程互相持有对方需要的锁,导致所有线程都无法继续执行。

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,他们都将无法推进下去,陷入永久等待状态,这种现象称为死锁。

6.怎么防止死锁?

可以使用避免加锁顺序破坏、使用定时锁等方法来避免死锁的发生。

死锁是多线程编程中常见的问题,可以采取以下几种方法来预防和避免:

  1. 避免使用共享资源:尽量避免使用共享资源,因为共享资源是导致死锁的主要原因之一。如果必须使用共享资源,可以考虑使用锁或者信号量来进行同步。
  2. 按照顺序获取锁:当多个线程需要获取多个锁时,应该按照一定的顺序获取锁,避免出现循环等待的情况。例如,线程A获取锁1后才能获取锁2,而线程B获取锁2后才能获取锁1,这种情况容易导致死锁。
  3. 使用定时锁:对于需要长时间持有锁的情况,可以考虑使用定时锁。定时锁可以在一定时间后自动释放锁,避免长时间持有锁导致死锁的情况。
  4. 使用锁的分级管理:将不同的锁分为不同的级别,高级别的锁可以获得更多的资源,低级别的锁只能获得少量的资源。当低级别的锁被占用时,只有等待高级别的锁被释放后才能继续执行。
  5. 使用死锁避免算法:死锁避免算法是一种预防死锁的算法,它通过限制线程的行为来避免死锁的发生。例如,银行家算法是一种常用的死锁避免算法,它通过检查线程的请求是否会导致死锁来决定是否满足线程的请求。
  6. 使用锁的粒度更细:将锁的粒度变得更细,可以减少线程之间的竞争,降低死锁的概率。例如,使用多个独立的锁来保护不同的资源,而不是使用一个全局的锁。
  7. 避免线程饥饿:当一个线程长时间无法获取到需要的资源时,可能会导致死锁的发生。因此,应该尽量避免线程饥饿的情况,合理分配资源给不同的线程。

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

ThreadLocal是一种线程本地变量,每个线程都拥有自己的变量副本,常用于实现线程封闭 和线程上下文信息传递。

ThreadLocal 是一个Java的类,它用于创建线程局部变量。线程局部变量是每个线程自己独有的变量,它不会在线程之间共享。ThreadLocal的实例通常是在类中以静态字段的方式存在的。

ThreadLocal 的使用场景主要有以下几类:

  1. 方便同一个线程使用某一对象,避免不必要的参数传递。
  2. 线程间数据隔离(每个线程在自己线程里使用自己的局部变量,各线程间的ThreadLocal对象互不影响)。
  3. 获取数据库连接、Session、关联ID等。例如在 Spring 的事务管理器中,会通过 ThreadLocal 存储事务对象,以保证每个线程都在各自的 Connection 上进行数据库操作,避免出现线程安全问题。

然而,需要注意的是,在管理环境下(如 Web 服务器)使用 ThreadLocal 时要特别小心。因为工作线程的生命周期比任何应用变量的生命周期都要长,如果 ThreadLocal 变量在工作完成后没有得到释放,可能会导致内存泄露的风险。

8.说一下 synchronized 底层实现原理?

synchronized使用了对象的内部锁(监视器锁),它可以用来修饰代码块或方法,保证在 同一时刻只有一个线程可以进入临界区。

synchronized 是 Java 语言中的关键字,用于实现同步锁。它的底层实现原理是通过对象内部的一个叫做监视器锁(monitor)来实现的,而监视器锁本质又是依赖于底层的操作系统的 MutexLock(互斥锁)来实现的。

当一个线程要执行一个 synchronized 方法时,它需要先获得锁才能执行该方法。如果该线程已经获得了锁,则可以直接执行该方法;否则,该线程会被挂起,等待其他线程释放锁。一旦有线程释放了锁,就会唤醒等待的线程,让其获得锁并执行。

synchronized 底层实现原理还包括对代码块的加锁和解锁。当线程执行到 synchronized 代码块时,需要先获得锁才能执行后面的代码块。当线程执行到 synchronized 代码块的末尾时,会自动释放锁。这样可以保证同一时间只有一个线程可以执行该代码块。

每个对象自身维护着一个被加锁次数的计数器,当计数器不为0时,只有获得锁的线程才能再次获得锁。这个计数器的作用是防止死锁的发生。如果一个线程已经获得了多次锁,那么在下一次尝试获取锁时,该线程必须等待其他线程释放锁,否则就会发生死锁。

另外,synchronized 底层实现原理还涉及到对方法进行隐式的加锁和解锁。当线程要执行的方法被标注上 synchronized 时,需要先获得锁才能执行该方法。这个锁可以通过 ACC_SYNCHRONIZED 关键字来实现。当线程执行到 synchronized 方法时,会自动获得锁并执行该方法。当线程执行完 synchronized 方法后,会自动释放锁。

总之,synchronized 是 Java 语言中实现同步的关键字之一,它的底层实现原理是通过监视器锁和 MutexLock 来实现的。通过对方法进行隐式的加锁和解锁、对代码块进行加锁和解锁以及对计数器的使用,可以有效地保证多线程程序的正确性和稳定性。

9.synchronized 和 volatile 的区别是什么?

synchronized是一种独占锁,可以实现原子操作和临界区的同步;volatile是一种轻量级的 同步机制,用于保证可见性和禁止指令重排序。

synchronized和volatile是Java中两种不同的线程同步机制,它们有以下区别:

  1. 作用机制:synchronized是在方法或代码块前加上同步锁,保证同一时刻只有一个线程可以执行该段代码。而volatile关键字则用于保证多线程对变量的访问一致性,它不会阻塞线程,而是通过在内存和CPU之间建立缓存一致性协议来保证变量的可见性。
  2. 锁的粒度:synchronized可以修饰方法或代码块,而volatile只能修饰变量。
  3. 内存语义:synchronized可以保证被修饰的方法或代码块在每个线程中的执行是按照顺序进行的,不会出现数据不一致的问题。而volatile则无法保证这一点。
  4. 性能:使用synchronized会带来额外的开销,因为它需要进行线程阻塞和唤醒的操作。而volatile则不需要进行这些操作,因此性能相对较好。
  5. 原子性:synchronized可以保证被修饰的方法或代码块具有原子性,即这些代码不可分割。而volatile无法保证原子性。

综上所述,synchronized和volatile各有优缺点,需要根据具体的使用场景来选择合适的同步机制。

10.synchronized 和 Lock 有什么区别?

synchronized是Java内置的关键字,自动管理锁的获取和释放;Lock是Lock接口的实现 类,需要手动管理锁的获取和释放,提供了更灵活的锁控制。

synchronized和Lock是Java中两种不同的线程同步机制,它们有以下区别:

  1. 关键字和接口的区别:synchronized是一个关键字,而Lock是一个接口。
  2. 加锁方式:synchronized是隐式的加锁,而Lock是显式的加锁。
  3. 作用范围:synchronized可以作用于方法上或者代码块上,而Lock只能作用于代码块上。
  4. 底层实现:synchronized底层使用的是objectMonitor,而Lock底层使用的是AQS。
  5. 支持的锁类型:synchronized是非公平锁,而Lock可以是公平锁也可以是非公平锁。
  6. 超时机制:synchronized没有超时机制,而Lock中的trylock可以支持超时机制。
  7. 可中断性:synchronized不可中断,而Lock中的lockInterruptibly可中断的获取锁。
  8. 等待和唤醒机制:synchronized使用object类的wait和notify进行等待和唤醒,而Lock使用condition接口进行等待和唤醒(await和signal)。
  9. 个性化定制:Lock支持个性化定制,使用了模板方法模式,可以自行实现lock方法。

综上所述,synchronized和Lock都是Java中实现线程同步的机制,它们各有优缺点,需要根据具体的使用场景来选择合适的同步机制。

11.synchronized 和 ReentrantLock 区别是什么?

synchronized是关键字,无法中断等待获取锁的线程;ReentrantLock是Lock接口的实现 类,可以中断等待获取锁的线程。

synchronized 和 ReentrantLock 是Java中两种不同的线程同步机制,它们有以下区别:

  1. 关键字和接口的区别:synchronized是一个关键字,而ReentrantLock是一个接口。
  2. 加锁方式:synchronized是隐式的加锁,而ReentrantLock需要显式地调用lock()和unlock()方法来加锁和解锁。
  3. 锁的释放:synchronized在Java编译器下自动释放锁,而ReentrantLock需要程序员手动释放锁。
  4. 公平性:synchronized不具有公平性,而ReentrantLock可以通过构造函数来设置公平性。
  5. 锁状态查询:ReentrantLock提供了一个isHeldByCurrentThread()方法可以查询当前线程是否持有锁,而synchronized则没有这个功能。
  6. 锁升级和降级:synchronized不支持锁升级和降级,而ReentrantLock可以通过Condition接口来实现锁升级和降级。
  7. 等待可中断性:synchronized不支持等待可中断性,而ReentrantLock可以通过Condition接口来实现等待可中断性。
  8. 锁的可重入性:synchronized和ReentrantLock都支持可重入锁。
  9. 锁的粒度:synchronized可以作用于方法或代码块上,而ReentrantLock只可以作用于代码块上。

综上所述,synchronized和ReentrantLock都是Java中实现线程同步的机制,它们各有优缺点,需要根据具体的使用场景来选择合适的同步机制。

22.说一下 atomic 的原理?

atomic包提供了一些原子操作类,通过CAS(Compare and Swap)操作实现了多线程环 境下的线程安全,确保操作的原子性

Atomic(原子性)是指一个操作是不可中断的,即使在多线程环境下也不会被其他线程干扰。在并发编程中,原子性是保证数据一致性的关键。

Atomic操作的实现原理主要包括原子指令、自旋锁、读写锁和原子变量等。原子指令可以保证指令执行的不可中断性,自旋锁可以通过不断循环来等待锁的释放,读写锁可以实现对共享资源的并发访问,原子变量则可以保证对共享数据的原子性操作。

在实现Atomic时,需要保证操作的数据是共享的,并且需要保证对数据的访问是原子的。因此,需要使用锁或者其他同步机制来保证操作的原子性和可见性。同时,还需要考虑操作的具体实现方式,例如使用硬件级别的原子指令、使用自旋锁、读写锁或者使用原子变量等。

总之,Atomic的实现原理是通过保证操作的原子性和可见性来保证数据的一致性和可靠性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1230039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Blender洪水淹没毁墙效果

本文中用到了两个Blender插件:FLIP Fluid(流体模拟相关插件) 和 RBDLab(碎裂插件): 1.用FLIP Fluid制作流体、域、障碍,确定好流体的冲刷方向(后期好摆放被摧毁的墙体),利用插件做出水流动画&a…

信息中心网络提出的背景、研究现状及研究内容

信息中心网络什么时候提出的?未来发展前景?有什么著名实验室在做? 1、提出背景: 互联网产生于上世纪60年代: (1)网络设备数量呈指数性增长 截至2022年底全球范围内预计将有超过280亿台终端设…

【openGauss/MogDB的TPCH测试】

TPC-H是一个决策支持基准(Decision Support Benchmark),它由一套面向业务的特别查询和并发数据修改组成。查询和填充数据库的数据具有广泛的行业相关性。这个基准测试演示了检查大量数据、执行高度复杂的查询并回答关键业务问题的决策支持系统…

MobaXterm配置ssh端口转发(tensorboard使用)

背景: 我有一台本地Windows电脑,上面安装了MobaXterm软件。 MobaXterm通过ssh连接了一台服务器(默认是通过22端口连,我这里配了一下,要填别的) 现在服务器在跑模型,其6006端口是tensorboard端口…

沸点 | Ultipa 图数据库金融应用场景优秀案例首批入选,金融街论坛年会发布

为推进图数据库在金融行业的创新应用试点,近日,在2023金融街论坛年会“全球金融科技中心网络年会暨ZIBS北京论坛”上,北京前沿金融监管科技研究院发布了基于国际标准组织——国际关联数据基准委员会(LDBC)的《图数据库…

安全+Linux!IBM新一代大型机Z14全新发布

导读本周,以“架构 人机同行”为主题的IBM Systems创行者高峰论坛在北京召开,IBM全球及大中华区硬件系统部负责人,金融、医疗、制造等领域的企业、合作伙伴共与这一年度盛会,探讨认知时代下的基础架构技术趋势及IBM硬件系统业务的…

【MySQL】_JDBC

目录 1. JDBC原理 2. 导入JDBC驱动包 3. 编写JDBC代码实现Insert 3.1 创建并初始化一个数据源 3.2 和数据库服务器建立连接 3.3 构造SQL语句 3.4 执行SQL语句 3.5 释放必要的资源 4. JDBC代码的优化 4.1 从控制台输入 4.2 避免SQL注入的SQL语句 5. 编写JDBC代码实现…

【SpringBoot3+Vue3】四【基础篇】-前端(vue基础)

目录 一、项目前置知识 二、使用vscode创建 三、vue介绍 四、局部使用vue 1、快速入门 1.1 需求 1.2 准备工作 1.3 操作 1.3.1 创建html 1.3.2 创建初始html代码 1.3.3 参照官网import vue 1.3.4 创建vue应用实例 1.3.5 准备div 1.3.6 准备用户数据 1.3.7 通过…

Matlab论文插图绘制模板第127期—进阶气泡矩阵/热图

​在之前的文章中,分享了Matlab散点图矩阵的绘制模板: 也分享过气泡矩阵图的绘制模板: 考虑到规范性和便捷性,再来分享一下进阶版的气泡矩阵/热图。 先来看一下成品效果: 特别提示:本期内容『数据代码』已…

PlayCover“模拟器”作弊解决方案

当下的游戏市场,移动游戏已占据了主导地位,但移动端游戏碍于屏幕大小影响操作、性能限制导致卡顿等因素,开始逐步支持多端互通。但仍有一些游戏存在移动端与 PC 端不互通、不支持 PC 端或没有 Mac 版本,导致 Mac 设备体验游戏不方…

通信原理板块——纠错编码的基本原理和性能

微信公众号上线,搜索公众号小灰灰的FPGA,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 1、分组码 将信息码分组&#xff0…

CleanMyMac X2024免费测试版好不好用?值不值得下载

如果你是一位Mac用户,你可能会遇到一些问题,比如Mac运行缓慢、磁盘空间不足、应用程序难以管理等。这些问题会影响你的Mac的性能和体验,让你感到沮丧和无奈。那么,有没有一款软件可以帮助你解决这些问题呢?答案是肯定的…

109.firefly-extboot的生成脚本

内核版本: 4.4.194 在firefly的sdk 2.5.1c及以后的版本都是extboot.img(对应表中的extboot) 但是之前的并不是,而且一个boot.img,(对应表中rkboot) rkboot的生成方法可以参考解决linux5.15编…

二、什么是寄存器

目录 一、STM32芯片架构简图及系统框图 1.1 STM32芯片架构简图 1.1.1 FLASH是什么,用来做什么 1.1.2 SRAM是什么,用来做什么 1.1.3 片上外设是什么,用来做什么 1.2 系统框图 1.2.1 驱动单元 1.2.2 被动单元 二、什么是寄存器 2.1 存…

Cannot find proj.db

原因 编译GDAL完成后,我打了个包(包括.so)移动到了另外同环境的机器上。 应用gdal ogr2ogr时候提示找不到proj.db 解决办法: 把proj的share拷贝到另外环境上。 #gdal新建othershare,proj的share复制过去 mkdir -p /usr/local/gdal-3.6.2…

通达信的ebk文件

我们在通达信软件中 调出 “自定义板块设置” 这个菜单,点击“导出”,会提示你存储 “自选股.EBK”,其实就是对自定义板块里的目录进行备份的一种方式, 当我们打开 这个文件,你会发现其实就是存储了 股票代码&#xff…

python 自动化福音,30行代码手撸ddt模块

用 python 做过自动化的小伙伴,大多数都应该使用过 ddt 这个模块,不可否认 ddt 这个模块确实挺好用,可以自动根据用例数据,来生成测试用例,能够很方便的将测试数据和测试用例执行的逻辑进行分离。 接下来就带大家一起…

微服务:何为RPC框架

前言 最近在看有关分布式和微服务的知识,首先第一个碰到的就是RPC框架,常见的RPC框架其实有很多,比较常见的比如:阿里的Dubbo、ApacheThrift、谷歌的gRPC、腾讯的tRPC等等。RPC作为远程调用协议在微服务架构中可以说是比较常见了&…

基于GATK流程化进行SNP calling

在进行变异检测时,以群体基因组重测序数据为例,涉及到的个体基本都是上百个,而其中大多数流程均是重复的步骤。 本文将基于GATK进行SNP calling的流程写入循环,便于批量分析。 1 涉及变量 1.工作目录work_dir/ 2.参考基因组ref…

每天一点python——day74

#每天一点Python——74 #函数调用的参数传递:位置与关键字函数参数传递指的是函数调用时候的传递 一般有两种: 位置实参传递 关键字实参传递#位置实参传递 #我们昨天定义了一个函数 def jiafa(a,b):#我们定义了两个参数,a和b,他们…