![](https://img-blog.csdnimg.cn/20201014180756926.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
面试
面试题复习
规则长方体固体物质空间移动工程师.
正是修行时!
展开
-
基础面试题——乐观锁和悲观锁的区别和优缺点
悲观锁是一种认为资源会被并发修改的锁策略,每次访问资源时都会加锁,保证只有一个线程能够访问资源,其他线程必须等待锁的释放。乐观锁是一种认为资源不会被并发修改的锁策略,在每次操作时不直接加锁,而是先假设数据不会被并发修改。如果资源被修改,操作失败并重试。悲观锁适用于并发冲突较多的场景,因为在这些场景下,频繁的锁争用可以有效地防止数据不一致。乐观锁的缺点是,在高并发环境中,冲突可能频繁发生,导致大量的重试,反而可能影响系统性能。乐观锁适用于并发冲突较少的场景,因为乐观锁可以减少锁争用,提升性能。原创 2024-08-14 20:09:25 · 181 阅读 · 0 评论 -
基础面试题——volatile是如何保证可见性和有序性的?
对于volatile变量进行读写的时候,Java 内存模型(JMM)会向处理器发送一条lock前缀的指令,volatile 关键字会在读写操作前后插入内存屏障,限制指令重排序,从而保证了代码执行的有序性。确保对该变量的写操作直接刷回主内存,而其他处理器由于遵守了缓存一致性协议,也会把这个变量的值从主存中加载到自己的缓存中,以此保证了可见性。原创 2024-08-14 19:35:08 · 76 阅读 · 0 评论 -
基础面试题——volatile能保证原子性吗?为什么?
volatile 主要用于保证变量的可见性、有序性(禁止指令重排序优化)。因为它不是锁,没做任何保证原子性的处理,当然不能保证原子性了。原创 2024-08-14 19:21:51 · 401 阅读 · 0 评论 -
基础面试题——synchronized是如何保证原子性,可见性,有序性的?
线程在执行synchronized内的代码时,即时CPU时间片用完,也不会释放锁,后续获取到CPU时间片会继续执行。在 synchronized 块中,线程在进入时会从主内存中读取共享变量的值到线程的个主内存,所有操作都在线程工作内存中进行,不能直接读写主存,线程之间也无法访问对方的工作内存变量。JMM内存模型规定了,所有变量都存储在主内存中,线程的工作内存中保存了变量的副本拷贝,这样确保了一个线程在释放锁后,另一个线程在获取锁时,能看到最新的变量值,保证了线程间对共享变量的可见性。原创 2024-08-14 00:25:42 · 183 阅读 · 0 评论 -
基础面试题—— synchronized锁的是什么?
如果多个线程同时调用同一个对象的 synchronized 实例方法,其中一个线程获得锁后,其他线程必须等待锁被释放。在静态方法上使用 synchronized,表示进入该方法前,线程必须获取当前类的类对象锁(Class对象)。在实例方法上使用 synchronized,表示进入该方法前,线程必须获取当前实例对象的锁(this)。静态方法上的锁是作用于类级别的,而不是单个实例,因此即使是不同实例的线程,也会互相阻塞。synchronized(ClassName.class):锁定当前类的类对象。原创 2024-08-13 23:57:41 · 194 阅读 · 0 评论 -
基础面试题—— synchronized是怎么实现的?
synchronized 是 Java 中的关键字,用于实现线程间的同步。它可以用于方法或代码块上,确保同一时刻只有一个线程可以执行被 synchronized 修饰的代码块或方法,从而避免多线程环境中的并发问题。原创 2024-08-13 23:42:52 · 386 阅读 · 0 评论 -
基础面试题——什么是Java内存模型JMM ?
线程间的变量的传递,均需要自己的工作内存和主内存之间进行数据同步,而JMM就作用于工作内存和主内存之间的数据同步过程,它规定了如何做数据同步以及什么时候做数据同步。JMM内存模型规定所有的共享变量都存储在主内存中,每个线程都有自己的工作内存,用于存储该线程私有的变量副本。JMM描述了在多线程环境下,各个线程如何通过内存进行交互,它规定了变量在内存中的存储方式,线程对变量的所有操作(读取、赋值等)都必须在线程工作内存中进行,线程不能直接操作主内存。不同的线程之间也无法直接访问对方工作内存中的变量。原创 2024-08-13 21:30:38 · 69 阅读 · 0 评论 -
基础面试题——什么是死锁? 如何解决?
线程已获得的资源在没有使用完毕之前,不能强行剥夺,资源只能由资源占有者主动释放。死锁是多个线程在执行过程中,因为争夺资源而造成的一种相互等待的状态。如果没有外力干涉,它们将永远等待下去,程序无法继续执行。一个线程因请求资源而阻塞时,对已获得的资源保持不释放。线程之间形成一种头尾相接的,循环等待资源的关系。想要预防和解除死锁,需要避免死锁4个条件同时发生。一个资源每次只能被一个线程占用。原创 2024-08-13 20:47:19 · 204 阅读 · 0 评论 -
基础面试题——线程同步的方式有哪些?
synchronized发生异常时,会自动释放线程占用的锁,故不会发生死锁现象。且具有更灵活的锁定机制,可以中断等待锁的线程,Lock发生异常,若没有主动释放,,允许一个或多个线程等待其它线程执行完毕后在执行,可用于线程之间的协调与通信。与 synchronized类似,也可以确保同一时间只有一个线程能访问。,让一组线程在一个栅栏处等待,直到所有线程都到达某个屏障点,才会继续执行。,可以修饰代码块或者方法,确保同一时间只有一个线程能访问。,控制同时访问某个资源的线程数量,可以用于限流或实现资源池。原创 2024-08-13 20:28:24 · 194 阅读 · 0 评论 -
基础面试题——什么是ThreadLocal ?如何实现的?
当调用 ThreadLocal.set(value) 时,ThreadLocal 实例会将值存储到当前线程的 ThreadLocalMap 中。当调用 ThreadLocal.get() 时,ThreadLocal 实例会从当前线程的 ThreadLocalMap 中检索存储的值。(需要注意内存泄漏问题,在使用完 ThreadLocal 实例后,应该调用 remove() 方法清理线程局部变量)常用于存储线程范围内的对象,比如用户会话信息等,这些对象在不同线程中是隔离的。ThreadLocal有四个方法。原创 2024-08-13 01:39:28 · 63 阅读 · 0 评论 -
基础面试题——多线程中run和start,wait和sleep,notify和notifyAll区别?
会唤醒所有在 wait() 状态的线程。是线程要执行的代码所在的方法,它本质上是普通方法,如果直接调用 run(),不会启动新线程,而是在当前线程中顺序执行 run() 方法中的代码。调用 wait() 时,线程会释放当前持有的锁和CPU资源,wait()方法只能在同步块或者同步方法中使用。notify()方法与notifyAll()方法,必须在同步块或同步方法中调用,并且线程必须持有对象的锁。用于启动一个新线程,调用 start() 后,run() 方法会在新的线程中执行。原创 2024-08-13 00:26:49 · 145 阅读 · 0 评论 -
基础面试题——什么是线程池?如何实现的?
是 Java 中用于管理和重用一组线程的机制。它通过维护一个线程的集合来执行任务,从而减少了频繁创建和销毁线程的开销,提高了应用程序的性能和响应速度Java还可以通过 Executors(执行器)工具类,可以方便地创建预定义的线程池,分别是:,超出的线程会在队列中等待。,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。原创 2024-08-12 19:33:55 · 352 阅读 · 0 评论 -
基础面试题——创建线程有几种方式?
在Java中,共有四种方式可以创建线程,分别是。原创 2024-08-11 23:32:23 · 95 阅读 · 0 评论 -
基础面试题——什么是守护线程和普通线程有什么区别
需要注意的是,必须在启动线程之前设置守护线程状态,否则会抛出 IllegalThreadStateException(非法线程状态异常)。是一种在后台运行的线程,它的生命周期依赖于前台的普通线程。当所有的普通线程都结束运行时,JVM 会自动退出,即使守护线程仍在运行中。守护线程(Daemon Thread) 和 普通线程(用户线程,User Thread) 是 Java 中的两类线程。当所有普通线程都结束时,即使守护线程仍然在运行,JVM 也会退出并终止所有守护线程。原创 2024-08-11 22:38:11 · 139 阅读 · 0 评论 -
基础面试题——线程有几种状态,状态之间的流转是怎样的?
常见的方法包括 Thread.sleep(long millis)、Object.wait(long timeout)、Thread.join(long millis) 等。线程处于这种状态通常是调用了 Object.wait()、Thread.join() 或 LockSupport.park() 方法。线程已经启动,正在运行或准备运行中。线程状态之间的流转是由各种同步、等待机制控制的,这些状态之间的流转反映了线程的生命周期。线程对象已经被创建,但还没有调用 start() 方法启动线程。原创 2024-08-11 22:24:04 · 179 阅读 · 0 评论 -
基础面试题——什么是多线程中的上下文切换
过多的线程频繁切换上下文信息会降低系统的运行效率,因此要尽可能减少上下文切换的次数,以提高系统的效率。共享CPU时间片,当一个线程的CPU时间片用完后,需要切换到另一个线程运行,此时需要保存当前。线程的状态信息,包括程序计数器,寄存器,栈指针等,以便于下一次恢复执行该线程时能够正确运行。我们的计算机是多用户多任务分时操作系统,上下文切换通常是指,在一个CPU上,由于多个线程。同时需要将获取到CPU时间片的线程状态信息恢复,以便于该线程能够正确执行。原创 2024-08-11 21:59:32 · 140 阅读 · 0 评论 -
基础面试题——Set是如何保证元素不重复的
元素在插入TreeSet时compareTo()方法要被调用,所以TreeSet中的元素要实现Comparable接口,是哈希表实现,HashSet中的数据是无序的,可以放入null,但只能放入一个null,底层基于HashMap。首先计算元素的HashCode值,通过HashCode值计算出元素的存储位置,如果位置为空,就添加进去;TreeSet 底层是TreeMap的keySet(),TreeMap是按照key排序的,是二叉树实现,TreeSet中的数据是自动排好序的,不允许放入null值,原创 2024-08-11 17:54:32 · 242 阅读 · 0 评论 -
基础面试题——ConcurrentHashMap为什么在JDK1.8中使用synchronized而不是ReentrantLock
--- 在 JDK 1.8 之前,ConcurrentHashMap 使用的是 ReentrantLock 来实现分段锁(Segment Locking),从而保证线程安全。synchronized 是JVM内置语义,JVM 的即时编译器(JIT)能在运行时做出相应的优化,可以进行锁粗化,锁消除,在无竞争的情况下自动去掉不必要的锁。synchronized 的使用让代码更加直观和易读,减少了因锁管理带来的复杂性,提高了代码的可维护性。而线程不需要被挂起时,可以减少上下文切换的开销。原创 2024-08-11 17:29:38 · 218 阅读 · 0 评论 -
基础面试题——什么是COW,如何保证的线程安全
COW(Copy-On-Write 写时复制) 的基本思想是在进行写操作时,不直接修改原数据,而是先复制一份副本,然后在副本上进行修改。写操作完成后,再将副本替换为原数据(这个替换操作是原子性的,以确保在任何时刻,所有读取操作都能读取到一致的数据。适合读多写少场景:在读多写少的场景下,COW 能有效减少锁的竞争,提高系统的并发性能。不适合写操作频繁的场景:频繁的写操作会导致大量的数据复制和内存占用,影响系统性能。一致性:所有读操作都能获取一致的数据视图,不会因为写操作而影响读取的结果。原创 2024-08-11 16:57:49 · 180 阅读 · 0 评论 -
基础面试题——ConcurrentHashMap是如何保证线程安全的
如果桶位置不为空,在链表或红黑树中更新节点时,ConcurrentHashMap 使用 synchronized 锁进行保护,以确保操作的原子性和线程安全。如果多个线程同时尝试插入,只有一个线程能够成功,其他线程会进行重试。只在必要时加锁,且锁粒度较小,仅作用于某个桶中的链表或树的头节点,而不是整个哈希表。在JDK1.8中,ConcurrentHashMap使用节点锁的思想,即采用"CAS + Synchronized"的。例如,在插入一个新的键值对时,如果目标桶的位置为空,原创 2024-08-11 16:39:07 · 114 阅读 · 0 评论 -
基础面试题——Stream的并行流是如何实现的
创建并行流,分割数据源将任务分解成多个子任务,将任务分发到多个线程并行执行,汇总各个子任务的结果,得到最终输出。创建:通过集合的 parallelStream() 或 stream.parallel() 创建并行流。分割任务:利用 Spliterator 分割数据源,将任务分解成多个子任务。执行任务:使用 ForkJoinPool 将任务分发到多个线程并行执行。合并结果:汇总各个子任务的结果,得到最终输出。原创 2024-08-11 16:04:40 · 101 阅读 · 0 评论 -
基础面试题——HashMap在 get() 和 put() 时经过那些步骤
get() 方法用于从 HashMap 中检索一个键对应的值。put() 方法用于将一个键值对插入到 HashMap 中。原创 2024-08-11 15:38:48 · 170 阅读 · 0 评论 -
基础面试题——HashMap和Hashtable和ConcurrentHashMap的区别
ConcurrentHashMap:不允许 null 键或 null 值,原因是 null 的存在可能会导致并发问题,例如无法区分返回值是因为键不存在还是键对应的值为 null。由于采用的是对整个 Hashtable 的方法级同步,因此在高并发情况下性能较差,可能出现大量线程竞争导致的性能瓶颈。底层实现与 HashMap 类似,也使用数组和链表的结构,但由于 Hashtable 是早期的类,没有红黑树的优化。在多线程环境中性能较好,它的锁分离机制允许多个线程并发访问不同部分,从而减少锁竞争。原创 2024-08-11 00:31:18 · 213 阅读 · 0 评论 -
基础面试题—— HashMap的数据结构和它的工作原理
的数据结构是由数组、链表和红黑树组成的混合结构HashMap 内部维护了一个数组,称为桶数组(bucket array)。每个数组元素称为一个桶(bucket),每个桶存放的是链表或红黑树的头结点。每个键值对都会通过键的哈希值(hash code)映射到这个数组中的一个桶内。这个过程通过计算 hash(key) 来确定具体的数组索引。当多个键通过哈希函数映射到同一个桶时(即发生哈希碰撞),这些键值对将会被存储在该桶对应的链表中。原创 2024-08-11 00:04:05 · 312 阅读 · 0 评论 -
基础面试题——ArrayList 和 LinkedList 集合的区别
由于是基于数组实现,ArrayList 在分配内存时会申请连续的内存块,且需要考虑数组扩容的问题。每个元素都是一个节点,节点包含了数据和指向前后节点的引用。LinkedList每个节点除了存储数据外,还存储了指向前后节点的引用,因此比 ArrayList 占用更多的内存,但它不需要连续的内存空间。ArrayList 和 LinkedList 集合都是List接口的实现类,它们都不是线程安全的,有不同的内部结构和使用场景。适合需要频繁插入或删除元素的场景,尤其是在列表中间插入或删除元素时。原创 2024-08-10 22:48:54 · 114 阅读 · 0 评论 -
基础面试题——什么是fail-fast(快速失效) 什么是fail-safe
例如:在集合类中,为了避免 ConcurrentModificationException并发修改异常 ,会维护一个“预期被修改次数”和“实际被修改次数” 在集合被修改时,会比较“预期被修改次数”和“实际被修改次数”的值,如果不一致则会触发。例如:CopyOnWriteArrayList 是一个 fail-safe 的集合,在修改时会先复制原出集合的内容,并不会直接对元集合进行修改。Java中默认的Java中的fail-fast(快速失效)机制,默认指的是一种错误检测机制,原创 2024-08-10 22:30:57 · 59 阅读 · 0 评论 -
基础面试题——Java的集合主要有那些,如何分类的
Map的主要实现分为 HashMap,Hashtable,ConcurrentHashMap 都是以KV键值对的形式使用。Queue(队列)则可以分为优先队列和双端队列等等,Map则可以分为普通的HashMap和可以排序的TreeMap等等。从功能上讲,List代表一个容器,可以是先进先出,也可以是先进后出。Collection 的主要实现有List,Set,Queue(队列)它们都是是单一元素集合。从实现上讲,List可以有链表或者数组实现,两者各有优劣,链表增删快,数组查询快。原创 2024-08-10 22:03:11 · 72 阅读 · 0 评论 -
基础面试题—— == 和 equals 的区别
= 操作符,可以比基础数据类型也可以比较引用数据类型,比较基础数据类型时比较的是具体的值,比较引用数据类型实际上比较的是内存地址。equals 方法 ,用于比较两个对象的内容是否相等。原创 2024-08-10 02:20:18 · 97 阅读 · 0 评论 -
基础面试题——为什么不能用BigDecimal的equals方法做等值比较
BigDecimal 的 equals 方法在比较时,会比较。而 compareTo 方法只比较。原创 2024-08-10 02:09:09 · 102 阅读 · 0 评论 -
基础面试题——什么是深拷贝和浅拷贝
是将一个对象复制到另一个变量中,对于基本数据类型,浅拷贝会复制它们的值;这意味着复制对象和原对象共享相同的内部引用对象,因此如果我们修改了复制对象中的基本类型属性,原始对象中不会受到影响,但如果修改了复制对象中的引用数据类型,原始对象对应的引用数据类型也会被修改。并将原始对象中的所有属性都复制到新对象中,因此如果我们修改了复制对象中的属性,原始对象中对应的属性不会受到影响,是一个完全独立的副本,互补影响。是将一个对象及其所有子对象都复制到另一个变量中,它会创建一个全新的对象,原创 2024-08-10 02:00:44 · 96 阅读 · 0 评论 -
基础面试题——Java是值传递还是引用传递
Java中所有的参数传递都是值传递,传递给方法的是参数的一个副本,而不是原始值本身,这一点适用于所有的参数类型,包括基础数据类型和对象引用。对于对象引用:传递的是引用的副本,方法内部可以通过这个副本引用,修改对象的内部状态,但无法改变引用指向的对象。对于基本类型:传递的是值的副本,对副本的修改不会影响原始值。原创 2024-08-10 01:26:27 · 66 阅读 · 0 评论 -
基础面试题——Java的动态代理如何实现
Java中的 Proxy(代理) 类 和 invocationHandler(调用处理程序)提供了生成动态代理类的能力。JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或者多个接口。还有一种是使用第三方类库提供的CGLIB。Java中实现动态代理的方式有2种。原创 2024-08-10 01:09:09 · 74 阅读 · 0 评论 -
基础面试题——什么是反射机制,为什么反射慢
反射可以在运行期做很多事情,但是代码的可阅读性低,不利于维护,代码性能低,由于反射涉及到动态解析的类型,因此不能执行某些Java虚拟机优化,反射在调用方法时,会从方法数组中遍历查找,这些动作都是耗时的,所以在业务代码中不推荐使用。Java中只要给定类的名字,就可以通过反射机制获取类所有的属性和方法。答:在运行时才确定的对象类型或方法信息,而不是在编译时静态确定的。反射是指,程序在运行期间可以获取自身信息。“动态解析的类型”是指什么?原创 2024-08-10 01:01:23 · 85 阅读 · 0 评论 -
基础面试题——String和StringBuffer和StringBuilder的区别
String 和 StringBuffer 是线程安全的,String 以字符串创建后的不可变性保证线程访问时的安全,StringBuffer底层方法是使用synchronized关键字来保证线程安全。StringBuffer 适用于在多线程环境中需要对字符串进行大量修改的场景,例如拼接、插入、删除等操作。String 是不可变的,StringBuffer 和 StringBuilder是可变的。StringBuilder 是非线程安全的,底层实现和StringBuffer 基本一致。原创 2024-08-10 00:51:35 · 62 阅读 · 0 评论 -
基础面试题——如何理解Java中的多态
多态是指,同一操作,作用于不同对象,可以有不同的解释,产生不同的结果,从而提升代码的灵活性和可扩展性。要实现多态,需要满足3个条件。原创 2024-08-10 00:43:37 · 85 阅读 · 0 评论