目录
19. 什么是 Java 中的 String、StringBuilder 和 StringBuffer 的区别?
21. HashMap 和 Hashtable 有什么区别?
31. 什么是 CAS(Compare-And-Swap)?
32.String buffer和String builder区别
37.ConcurrentHashMap原如何保证的线程安全?
38. 如何实现一个线程安全的单例模式(使用双重检查锁定)?
39. Java 中的 volatile 和 synchronized 有何区别?
40. 解释一下什么是 Java 中的“类加载器委托模型”。
46. Java 中的 CAS(Compare-And-Swap)原理是什么?
47. Java 中的 NIO(New I/O)和 IO 有什么区别?
48. Java 中的 CompletableFuture 是什么?
51. Java 中的“协变返回类型”和“逆变参数类型”是什么?
54. Java 中的 CyclicBarrier 和 CountDownLatch 有什么区别?
58.简述java内存分配与回收策略以及Minor GC和Major GC(full GC)
61.对ThreadLocal的理解,ThreadLocal内存泄漏问题
81. JDBC中的Statement、PreparedStatement和CallableStatement有什么区别?
89. MySQL中的自增(AUTO_INCREMENT)是什么?
1.接口与抽象类的区别
接口主要用于定义行为的规范,类可以实现多个接口,接口中的方法默认是 public 和 abstract(除非使用 default 或 static 关键字)。接口不能包含成员变量,但可以包含常量。
抽象类是类的一个不完全实现,可以包含具体方法(有实现的方法)和抽象方法(没有实现的方法)。抽象类支持构造方法和成员变量,并且一个类只能继承一个抽象类。
总结:接口关注行为规范,支持多实现;抽象类提供部分实现,支持单继承。
2. 什么是 Java 中的包装类?
答案:包装类是 Java 为每种基本数据类型提供的类,允许基本数据类型被视为对象。例如:Integer 包装 int,Double 包装 double。
3. 什么是 JVM?
答案:JVM(Java Virtual Machine)是 Java 的虚拟机,负责加载和执行 Java 字节码。它提供了跨平台能力,使得 Java 程序可以在不同操作系统上运行。
4. JVM 垃圾回收机制是如何工作的?
答案:JVM 垃圾回收(GC)通过自动回收不再使用的对象来管理内存。GC 使用的算法有标记-清除、标记-整理、复制算法等。垃圾回收的目的在于释放内存并避免内存泄漏。
5. 什么是 Java 中的异常?
答案:异常是程序运行时出现的错误或异常情况,Java 中的异常分为两类:检查异常(checked exceptions)和非检查异常(unchecked exceptions)。检查异常必须处理,非检查异常(如运行时异常)可以选择不处理。
6. 什么是类和对象?
答案:类是对象的模板或蓝图,它定义了对象的属性和方法。对象是类的实例化,是在内存中创建的类的具体实现。
7. Java 中的多态是什么?
答案:多态是指同一个方法或操作作用于不同的对象时,表现出不同的行为。在 Java 中,多态通过方法重载和方法重写实现。
8. 什么是方法重载?
答案:方法重载是指在同一个类中定义多个具有相同名称但参数不同的方法。方法重载是编译时多态的表现。
9. 什么是方法重写?
答案:方法重写是指子类重写父类的方法,方法签名相同,但子类提供了自己的实现。方法重写是运行时多态的表现。
10. 什么是接口?
答案:接口是 Java 中一种抽象类型,它定义了一组没有实现的方法,类可以实现接口并提供具体的实现。接口是 Java 中实现多重继承的一种方式。
11. Java 中的继承是什么?
答案:继承是面向对象编程中的一种机制,子类可以继承父类的属性和方法,从而实现代码的复用和扩展。
12. Java 中的抽象类是什么?
答案:抽象类是不能被实例化的类,它可以包含抽象方法(没有实现的方法)和具体方法。抽象类通常作为其他类的父类,定义公共的接口或行为。
13. Java 中的 super 关键字的作用是什么?
答案:super 关键字用于访问父类的属性、方法和构造方法,常用于子类访问父类的成员或调用父类的构造函数。
14. Java 中的 this 关键字的作用是什么?
答案:this 关键字表示当前对象的引用。常用于区分当前对象的成员变量和方法参数,或者在构造方法中调用当前类的其他构造方法。
15. 什么是线程?
答案:线程是程序中的执行路径。每个 Java 程序至少有一个主线程,程序可以通过创建新的线程来实现并发执行。
16. 如何创建一个线程?
答案:可以通过继承 Thread 类或实现 Runnable 接口来创建线程。继承 Thread 类需要重写 run() 方法,或者实现 Runnable 接口并将其传递给 Thread 实例。
17. 什么是同步?
答案:同步是指多个线程共享资源时,避免竞争条件的一种机制。在 Java 中,可以使用 synchronized 关键字来保证线程安全。
18. 什么是死锁?
答案:死锁是指两个或多个线程在争夺资源时,形成一种环形依赖,导致所有线程都无法继续执行。避免死锁的常见方法是加锁时遵循一定的顺序。
19. 什么是 Java 中的 String、StringBuilder 和 StringBuffer 的区别?
答案:String 是不可变的,每次修改都会创建新的对象。
StringBuilder 和 StringBuffer 都是可变的,但 StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的。
20. Java 中的集合框架包括哪些接口和类?
答案:
树形集合:Set(HashSet、LinkedHashSet、TreeSet)、List(ArrayList、LinkedList)
映射集合:Map(HashMap、LinkedHashMap、TreeMap)
队列集合:Queue(PriorityQueue、LinkedList)
21. HashMap 和 Hashtable 有什么区别?
答案:
HashMap 允许 null 键和 null 值,而 Hashtable 不允许。
HashMap 是非线程安全的,而 Hashtable 是线程安全的。
22. 什么是 final 关键字?
答案:
final 用于定义常量、方法和类。
常量:修饰变量,表示该变量的值不可修改。
方法:修饰方法,表示该方法不能被重写。
类:修饰类,表示该类不能被继承。
23. 什么是 static 关键字?
答案:static 关键字用于修饰类的成员(变量和方法),表示该成员属于类而不是类的实例。静态成员在类加载时就已存在,可以通过类名直接访问。
24. 什么是泛型?
答案:泛型是 Java 中的一种机制,可以在类、接口和方法中使用类型参数,使得代码更加灵活且类型安全。例如,List<T> 表示一个泛型列表,可以容纳任何类型的元素。
25. Java 中的反射是什么?
答案:反射是 Java 提供的一种机制,允许程序在运行时查询和修改类的信息(如类名、方法、字段等)。反射通过 Class 类和 Method、Field 等类来实现。
26. Java 中的枚举是什么?
答案:枚举是 Java 提供的一种类型,表示一组常量。使用 enum 关键字定义枚举类,枚举类的实例是有限的、固定的常量集合。
27. 什么是线程池?
答案:线程池是一种多线程并发执行任务的机制。线程池维护一定数量的线程,用于执行提交的任务,避免频繁创建和销毁线程的开销。Java 提供了 ExecutorService 接口和 ThreadPoolExecutor 类实现线程池。
28. 什么是 Java 中的 Lambda 表达式?
答案:Lambda 表达式是 Java 8 引入的特性,它提供了一种简洁的方式来表示匿名函数或单方法接口的实现。Lambda 表达式可以简化代码并提高可读性。
29. 什么是 Stream API?
答案:Stream API 是 Java 8 引入的一个新特性,允许开发者以声明式的方式操作集合数据。Stream API 可以通过管道操作进行数据转换和过滤,提高了代码的简洁性和可读性。
30.==和equals的区别
答案:==比较基本类型,比较的是值,==比较引用类型,比较的是内存地址
equlas是Object类的方法,本质上与==一样,但是有些类重写了equals方法,比如String的equals被重写后,比较的是字符值,另外重写了equlas后,也必须重写hashcode()方法
31. 什么是 CAS(Compare-And-Swap)?
答案:CAS(比较并交换)是一种无锁的原子操作,用于处理共享变量的更新问题。在 CAS 中,操作包括:
比较内存中的值是否等于预期值(比如变量当前的值)。
如果相等,更新内存中的值为新值。
如果不相等,操作失败,通常会重试直到成功。
CAS 是一种非常高效的并发控制机制,用于实现原子性操作,广泛应用于无锁数据结构(如 java.util.concurrent 包中的 Atomic 类)。
32.String buffer和String builder区别
StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,
只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全而StringBuffer则每次都需要判断锁,效率相对更低
33.ArrarList和LinkedList区别
ArrayList 和 LinkedList 都是实现了 List 接口的类,但它们的底层结构和性能特性有所不同:
底层结构:
ArrayList 使用动态数组存储元素,支持随机访问。
LinkedList 使用双向链表,每个元素都有前后节点指针。
访问效率:
ArrayList 提供 O(1) 时间复杂度的随机访问(通过索引访问元素)。
LinkedList 提供 O(n) 的访问时间复杂度,因为需要从头或尾遍历链表到指定位置。
插入和删除效率:
ArrayList 在插入或删除元素时,可能需要移动大量元素,因此通常是 O(n) 时间复杂度。
LinkedList 插入和删除元素时只需要调整指针,时间复杂度为 O(1),但需要遍历链表来找到位置。
内存使用:
ArrayList 需要预分配一定的内存空间,通常内存使用较紧凑。
LinkedList 每个元素都需要额外的内存来存储前后节点的引用,内存消耗较高。
总结:选择 ArrayList 还是 LinkedList 取决于操作的性质。如果主要进行随机访问,ArrayList 更合适;如果主要进行插入和删除操作,LinkedList 更优
34.什么是死锁,死锁产生的条件?如何避免死锁?
死锁就是一组互相竞争资源的线程,因为互相等待又互不相让资源,导致永久阻塞无法进行下去的情况
死锁产生的条件有四个:
互斥条件:资源x和y只能分别被一个线程占用
占有且等待:线程t1占有资源x后,等待资源y被释放,同时自己不释放资源x
不可抢占:其他线程不能强行抢占线程t1占有的资源
循环等待:线程t1等待线程t2占有的资源,线程t2等待线程t1占有的资源
避免死锁的方法(破坏对应的条件):
一次性申请所有资源(破坏互斥条件)
占有资源的线程,在申请其他资源时,如果申请失败,可以主动释放自己的资源(破坏占有且等待条件)
按照顺序去申请资源,然后反序释放资源,破坏循环等待条件
35.synchronized和volatile有什么区别
synchronized和 volatile都用于多线程环境中,但用途和实现方式不同:
1. 用途:
synchronized:用于保证对共享资源的互斥访问,确保同一时刻只有一个线程执行临界区代码,保证数据一致性。
volatile:确保共享变量的可见性,即一个线程修改的值对其他线程立即可见,但不保证原子性。
2. 实现方式:
synchronized:通过锁机制,阻止多个线程同时访问共享资源。
volatile:通过特殊的内存访问机制,避免缓存,确保变量在主内存中的最新值对其他线程可见。
3. 原子性:
synchronized:可以保证代码块的原子性(即互斥执行)。
volatile:不保证原子性,多个线程同时修改可能导致竞态条件。
4. 性能:
synchronized:性能开销较大,尤其在高并发时可能导致锁竞争。
volatile:性能较好,但只能用于简单的变量操作。
5. 适用场景:
synchronized:适用于需要互斥访问和保证原子性的场景。
volatile:适用于单一变量的可见性问题,如标志位的更新。
总结:synchronized 用于控制访问和保证原子性,volatile 用于确保变量的可见性,但不解决原子性问题。
36.Http 常见的状态码
HTTP 状态码用于表示服务器对客户端请求的处理结果,状态码由 3 位数字组成,并分为五个类别。以下是一些常见的 HTTP 状态码:
1. 1xx:信息性状态码
这些状态码表示请求已被接收,继续处理。
100 Continue:客户端可以继续发送请求,服务器已接收请求头,并且客户端可以继续发送请求体。
101 Switching Protocols:服务器已经理解并正在遵从客户端的请求,进行协议切换。
2. 2xx:成功状态码
这些状态码表示请求已成功处理。
200 OK:请求成功,通常用于 GET 或 POST 请求,表示响应体中包含请求的内容。
201 Created:请求成功并导致新资源的创建,通常用于 POST 请求。
204 No Content:请求成功,但没有返回任何内容,通常用于 DELETE 请求或成功但不需要返回数据的操作。
202 Accepted:请求已接受,但尚未处理完成,通常用于异步操作。
3. 3xx:重定向状态码
这些状态码表示客户端需要采取进一步的操作才能完成请求。
301 Moved Permanently:请求的资源已被永久移至新位置,返回的响应中会包含新的 URL。
302 Found(之前称为 Moved Temporarily):请求的资源临时移动到其他位置,客户端应继续使用原来的 URL 进行未来的请求。
304 Not Modified:资源未修改,客户端可以使用缓存的版本,不需要下载新的内容。
307 Temporary Redirect:与 302 类似,但要求客户端使用原来的 HTTP 方法重定向请求。
4. 4xx:客户端错误状态码
这些状态码表示请求有错误,通常是客户端错误导致的。
400 Bad Request:请求无效,服务器无法理解客户端的请求。
401 Unauthorized:请求需要身份验证,客户端未提供有效的身份验证信息。
403 Forbidden:服务器理解请求,但拒绝执行它,客户端没有访问权限。
404 Not Found:请求的资源未找到。
405 Method Not Allowed:请求的 HTTP 方法不被允许,例如使用 POST 请求访问一个只允许 GET 请求的资源。
408 Request Timeout:客户端请求超时,服务器等待客户端请求的时间超出预设的时间限制。
409 Conflict:请求与服务器上的当前状态冲突,通常用于更新资源时发生冲突。
410 Gone:请求的资源已经被永久删除,且没有可用的替代资源。
413 Payload Too Large:请求的实体过大,服务器无法处理。
415 Unsupported Media Type:请求的媒体类型不被服务器支持。
5. 5xx:服务器错误状态码
这些状态码表示服务器处理请求时发生了错误,通常是服务器端的故障。
500 Internal Server Error:服务器内部错误,无法完成请求。
502 Bad Gateway:服务器作为网关或代理时,接收到上游服务器的无效响应。
503 Service Unavailable:服务器当前无法处理请求,通常是因为服务器过载或正在进行维护。
504 Gateway Timeout:服务器作为网关或代理时,未及时从上游服务器获得响应。
505 HTTP Version Not Supported:服务器不支持请求中所用的 HTTP 协议版本。
37.ConcurrentHashMap原如何保证的线程安全?
JDK1.7:使用分段锁,将一个Map分为了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁
JDK1.8:采用CAS+Synchronized保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参与扩容;删除方法用了synchronized修饰,保证并发下移除元素安全
38. 如何实现一个线程安全的单例模式(使用双重检查锁定)?
答案:使用双重检查锁定(Double-Checked Locking)来实现懒加载的线程安全单例。具体代码如下:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
关键点是使用 volatile 关键字来保证内存可见性。
39. Java 中的 volatile 和 synchronized 有何区别?
答案:volatile 关键字只确保变量的可见性,保证一个线程对该变量的写操作对其他线程可见,但不保证原子性。而 synchronized 既保证了可见性,也保证了原子性。synchronized 会导致线程在进入同步块时进行加锁和释放锁,从而具有性能开销。
40. 解释一下什么是 Java 中的“类加载器委托模型”。
答案:Java 使用类加载器的委托机制来加载类,遵循从父类加载器向子类加载器委托的原则。即当一个类加载器加载一个类时,首先会将请求委托给父类加载器,如果父类加载器无法加载该类,才会由当前类加载器加载。这个机制可以防止类加载器之间的冲突。
41. JVM 中的“内存泄漏”是什么?如何避免?
答案:内存泄漏指的是对象不再被使用,但是由于某些引用的存在,它无法被垃圾回收器回收,导致内存无法释放。避免内存泄漏的常见方法包括:避免长时间持有对象引用、合理使用弱引用(WeakReference)、避免静态集合类引用等。
42. Java 中的 fork/join 框架是什么?
答案:fork/join 框架是 Java 7 引入的并行编程框架,旨在利用多核 CPU 提高计算密集型任务的性能。通过将任务分解成小任务并并行执行,最后合并结果来提高性能。ForkJoinPool 是该框架的核心类。
43. 简述 Java 中的垃圾回收算法。
答案:Java 中的垃圾回收算法包括:标记-清除(Mark-Sweep)、标记-整理(Mark-Compact)和复制算法。现代 JVM 使用的是分代收集算法,主要包括年轻代(Young Generation)、老年代(Old Generation)和永久代(PermGen,Java 8 后变为 Metaspace)。年轻代使用复制算法,老年代使用标记-清除或标记-整理算法。
44. JVM 如何进行内存管理?
答案:JVM 内存管理包括堆内存、栈内存、方法区(包括元数据)和本地方法栈。堆内存用于存放对象,栈内存存放局部变量和方法调用。JVM 通过垃圾回收器(GC)自动管理堆内存,回收不再被引用的对象。
45. 解释 Java 中的死锁、活锁和饥饿的区别。
答案:
死锁(Deadlock):多个线程在等待对方释放资源,导致所有线程都无法继续执行。
活锁(Livelock):线程虽然可以继续执行,但由于不断的相互响应或让步,最终没有完成任务。
饥饿(Starvation):某些线程得不到执行的机会,通常是因为调度优先级过低或者资源被其他线程长时间占用。
46. Java 中的 CAS(Compare-And-Swap)原理是什么?
答案:CAS 是一种无锁的原子操作,比较内存位置的值与期望值是否相等,如果相等就更新该内存位置的值。CAS 通常用在并发编程中,如 AtomicInteger 等类的实现中。CAS 本身虽然是原子的,但可能会遇到 ABA 问题(即值从 A 变为 B 再变回 A),需要借助版本号来解决。
47. Java 中的 NIO(New I/O)和 IO 有什么区别?
答案:IO 是传统的基于流的输入输出,操作是阻塞的;NIO 是新引入的基于通道和缓冲区的 I/O,支持非阻塞 I/O,允许多路复用,使得处理大量连接时性能更好。
48. Java 中的 CompletableFuture 是什么?
答案:CompletableFuture 是 Java 8 引入的一个用于处理异步任务的类。它允许你以更加声明性的方式组合多个异步操作,支持链式调用、回调函数、异常处理等。CompletableFuture 使得异步编程更加简洁和易于管理。
49. 解释一下 Lambda 表达式是如何工作的?
答案:Lambda 表达式是 Java 8 引入的特性,用于表示一个匿名方法的实例。它通过 () -> {} 语法实现,简化了函数式接口的实现。Lambda 会被编译成 InvokeDynamic 指令,以实现延迟绑定。
50. Java 中的“函数式编程”特性是什么?
答案:Java 8 引入了函数式编程特性,如 Lambda 表达式、Stream API 等,允许以声明式方式处理集合数据。函数式编程强调无副作用的函数调用、不可变数据和高阶函数的使用。
51. Java 中的“协变返回类型”和“逆变参数类型”是什么?
答案:
协变返回类型(Covariant Return Type):子类重写父类方法时,可以返回父类方法返回类型的子类。
逆变参数类型(Contravariant Parameter Type):方法参数的类型在子类中可以是父类方法参数类型的超类。
52. 如何分析 Java 程序的性能瓶颈?
答案:性能瓶颈分析的常见方法包括:
使用 JProfiler、VisualVM 等工具进行性能分析。
使用 JMH 进行基准测试,测量代码执行的时间。
分析 JVM 的 GC 日志,查看是否存在内存问题。
通过查看线程栈,确定是否有死锁或线程竞争问题。
53. Java 中的“对象池”是什么?
答案:对象池是一个用于重用对象的设计模式,避免频繁创建和销毁对象的开销。通过复用对象,减少内存分配的次数,常见的对象池包括数据库连接池、线程池等。
54. Java 中的 CyclicBarrier 和 CountDownLatch 有什么区别?
答案:
CyclicBarrier:允许一组线程在某个点上互相等待,直到所有线程都到达该点,适用于多线程的重复操作。
CountDownLatch:用于一个或多个线程等待其他线程完成某些操作后才能继续执行,计数器从指定值递减,适用于线程同步等待。
55. 解释一下 volatile 关键字的内存语义。
答案:volatile 关键字保证变量在多线程环境下的可见性。当一个线程修改 volatile 变量时,其他线程立即可以看到该修改。但 volatile 不保证原子性,它不能替代 synchronized 来保证操作的原子性。
56. Java 中的“内存模型”是如何保证线程安全的?
答案:Java 内存模型(JMM)通过定义共享变量的可见性、顺序性和原子性来保证线程安全。它通过 happens-before 规则来保证线程操作的有序性。例如,synchronized 和 volatile 都有明确的 happens-before 语义,确保变量修改的可见性和操作顺序。
57. Java 中的反射是如何工作的?
答案:反射是指在程序运行时动态地获取类的信息(如构造方法、方法、字段等)并操作它们。通过 Class 类可以获取类的结构信息(例如,方法、字段、构造)
58.简述java内存分配与回收策略以及Minor GC和Major GC(full GC)
Java 的内存管理通过 JVM 自动进行,主要依赖垃圾回收机制(GC)来回收不再使用的对象。JVM 内存分为几个区域:方法区、堆、栈等。堆区分为年轻代和老年代,GC 主要作用于年轻代和老年代。
内存分配
年轻代:新创建的对象分配在年轻代的 Eden 区,经过几次垃圾回收后,存活的对象转移到 Survivor 区,最后晋升到老年代。
老年代:长时间存活的对象最终进入老年代,GC 不那么频繁。
垃圾回收
Minor GC:回收年轻代,通常因为 Eden 区满了。停顿短,影响较小。
Major GC(Full GC):回收老年代和年轻代,通常因为老年代满了,停顿时间长,可能影响性能。
优化建议
调整堆大小(-Xms 和 -Xmx)减少 GC 次数。
选择合适的垃圾回收器(如 G1 GC)以优化性能。
简而言之,Minor GC 回收年轻代,Full GC 回收整个堆,合理配置内存和 GC 策略可以提升性能。
59.简单的谈一下SpringMVC的工作流程
SpringMVC 的工作流程包括以下几个步骤:
请求到达 DispatcherServlet:用户请求首先通过前端控制器 DispatcherServlet。
HandlerMapping 查找处理器:DispatcherServlet 根据请求的 URL 调用相应的 HandlerMapping 查找对应的控制器(Controller)。
调用 Controller 方法:DispatcherServlet 调用控制器的处理方法,并传入请求参数。
处理请求并返回 ModelAndView:Controller 处理完请求后,返回一个 ModelAndView 对象,其中包含了视图名和模型数据。
视图解析:DispatcherServlet 将视图名传递给 ViewResolver,解析成具体的视图对象。
渲染视图:视图负责渲染最终的 HTML 内容并返回给客户端。
60.简述SpringMVC中如何返回JSON数据
在 SpringMVC 中,可以通过 @ResponseBody 注解来直接返回 JSON 数据。通常步骤如下:
在 Controller 的方法上使用 @RequestMapping 和 @ResponseBody 注解。
方法返回对象或集合,SpringMVC 会自动通过 Jackson 或其他 JSON 序列化库将返回的对象转换为 JSON 格式并写入响应体。
61.对ThreadLocal的理解,ThreadLocal内存泄漏问题
ThreadLocal 是 Java 提供的一种机制,它允许每个线程有自己独立的变量副本,每个线程可以通过 get() 和 set() 方法访问该副本,而不会影响其他线程。ThreadLocal 在多线程编程中非常有用,如数据库连接、用户会话等场景。
内存泄漏问题:ThreadLocal 在使用时需要注意内存泄漏问题。如果线程池中线程长时间存活,而 ThreadLocal 变量没有及时清理,可能会导致内存泄漏。因为线程局部变量持有线程的引用,线程结束后,如果没有显式调用 remove() 方法清理,ThreadLocal 对象会导致无法回收的内存。
62.垃圾回收是否涉及栈?
垃圾回收(GC)主要涉及堆内存,而栈内存由线程使用来存储局部变量和方法调用的栈帧。栈中的内存不需要垃圾回收,因为栈是由系统自动管理的,每当方法调用和返回时,栈帧会自动入栈和出栈,生命周期较短。
63.栈内存越大越好吗?
栈内存过大会导致每个线程的内存开销增大,影响系统性能。栈内存太小则可能引发栈溢出错误。栈的大小应该适中,通常由操作系统或JVM根据线程需求动态分配。
64.方法内部的局部变量是否线程安全?
方法内部的局部变量是线程安全的,因为它们在每个线程中都有独立的副本。不同线程之间的局部变量相互隔离,不会发生竞争条件。
65.什么情况下会栈溢出?
栈溢出通常发生在递归调用过深,或者每个线程的栈空间不足时。例如,递归调用没有终止条件,导致栈帧不断压入,最终引发栈溢出错误。
66.进程和线程的区别,进程间如何通信
进程是操作系统分配资源的基本单位,每个进程都有独立的内存空间。线程是进程中的一个执行单元,同一进程内的线程共享进程的内存空间。进程间通信(IPC)通常通过管道、消息队列、共享内存、套接字等机制进行。
67.什么是线程上下文切换
线程上下文切换是指操作系统在多线程并发执行时,为了切换到另一个线程,保存当前线程的状态并加载下一个线程的状态。上下文切换涉及保存和恢复寄存器、程序计数器等信息,频繁切换会带来性能开销。
68.什么是死锁
死锁是指两个或多个线程在执行过程中,由于争夺资源而导致的互相等待的状态,从而无法继续执行下去,造成系统停滞。
69.死锁的必要条件
死锁的四个必要条件是:
- 互斥条件:资源不能被多个线程同时占用。
- 请求与保持条件:线程持有一个资源并请求其他资源。
- 不可剥夺条件:资源不能被强行从线程手中剥夺。
- 循环等待条件:多个线程互相等待形成环形依赖。
70.Synchrpnized和lock的区别
synchronized
是一种内置锁,Java提供的关键字,简单易用,但不够灵活。Lock
是 java.util.concurrent 包下的接口,提供了更细粒度的控制(如尝试加锁、定时加锁),可以手动释放锁并支持中断。
71.什么是AQS锁?
AQS(AbstractQueuedSynchronizer)是 Java 中的一个同步框架,它通过队列来管理请求共享或独占锁的线程。AQS 提供了基于 FIFO 队列的锁管理机制,支持自定义同步器如 ReentrantLock
和 CountDownLatch
等。
72.为什么AQS使用的双向链表?
AQS 使用双向链表来存储等待锁的线程。双向链表允许在不同条件下高效地移除和添加等待线程,能够快速执行唤醒操作,也有利于避免死锁等问题。
73.有哪些常见的AQS锁
常见的 AQS 锁包括:
ReentrantLock
:可重入锁,支持公平锁和非公平锁。ReadWriteLock
:读写锁,支持多个线程并发读,写操作是排他性的。Semaphore
:信号量,控制访问资源的数量。CountDownLatch
:倒计时锁,用于同步一组线程的执行。
74.sleep()和wait()的区别
sleep() 让当前线程暂停执行指定时间,不释放锁;wait() 是线程在同步块或方法内调用,释放当前持有的锁,直到被其他线程通过 notify() 或 notifyAll() 唤醒。
75.yield()和join()区别
yield()
让当前线程让出 CPU 时间片,给其他同等优先级的线程执行,但不释放锁;join()
使当前线程等待另一个线程执行完毕后再继续执行,通常用于线程的协作。
75. Java如何连接MySQL数据库?
Java可以通过JDBC(Java Database Connectivity)连接MySQL数据库。首先,必须在项目中添加MySQL的JDBC驱动包(如mysql-connector-java)。然后,通过DriverManager.getConnection()方法,使用数据库的URL、用户名和密码建立连接。示例代码如下:
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
76. 什么是JDBC?
JDBC(Java Database Connectivity)是Java提供的一个API,用于在Java程序中与各种数据库进行交互。通过JDBC,Java程序可以发送SQL语句、获取查询结果、更新数据等操作。JDBC通过Connection、Statement、ResultSet等接口提供了标准化的数据库操作。
77. JDBC连接池是什么?
JDBC连接池是一种通过池化管理数据库连接的技术。它避免了每次数据库操作时都需要创建新连接的开销,通过复用连接来提高性能。常见的连接池框架包括Apache DBCP、C3P0和HikariCP。
78. 如何配置JDBC连接池?
配置JDBC连接池通常包括指定数据库URL、用户名、密码、最大连接数、最大空闲时间等参数。以HikariCP为例,可以通过HikariConfig配置连接池,示例如下:
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("password");
HikariDataSource dataSource = new HikariDataSource(config);
79. MySQL数据库的连接URL格式是什么?
MySQL的连接URL格式如下:
jdbc:mysql://[host]:[port]/[database_name]?useSSL=[true/false]&serverTimezone=[timezone]
例如,连接到本地的MySQL数据库mydb,使用默认端口3306,URL为:
jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
80. MySQL中的事务是什么?
事务(Transaction)是指一组SQL操作,要么全部成功,要么全部失败。MySQL支持ACID特性,即原子性、一致性、隔离性和持久性。Java中可以通过JDBC的Connection.setAutoCommit(false)关闭自动提交,手动控制事务的提交和回滚。
81. JDBC中的Statement、PreparedStatement和CallableStatement有什么区别?
Statement用于执行简单的SQL查询,容易受到SQL注入的攻击。
PreparedStatement是Statement的子接口,用于执行预编译的SQL语句,具有更好的性能和安全性。
CallableStatement用于执行存储过程,支持输入输出参数。
82. 如何防止SQL注入攻击?
SQL注入攻击可以通过使用PreparedStatement而不是Statement来防止。PreparedStatement通过预编译SQL语句并绑定参数,避免了将用户输入直接拼接到SQL语句中,防止了恶意代码的注入。
83. 什么是MySQL的索引?
MySQL索引是一种数据结构,用于提高查询操作的速度。索引类似于书籍的目录,通过快速定位数据来减少查询时间。常见的索引类型有单列索引、多列索引、唯一索引、全文索引等。
84. MySQL的外键约束是什么?
外键(Foreign Key)是指一个表中的列引用了另一个表的主键或唯一键,用于保证数据的参照完整性。通过外键约束,可以防止插入无效数据以及删除仍被引用的记录。
85. MySQL中的ACID特性是什么?
ACID特性指的是数据库事务必须具备的四个属性:
原子性:事务中的所有操作要么全部成功,要么全部失败。
一致性:事务执行前后,数据库的状态是一致的。
隔离性:并发执行的事务互不干扰,每个事务的操作对其他事务是隔离的。
持久性:事务一旦提交,其结果是永久性的,即使系统崩溃也不会丢失。
86. 什么是MySQL的主从复制?
MySQL的主从复制是指通过复制机制将一个数据库(主库)的数据同步到其他数据库(从库)。主库负责写操作,从库负责读取操作。主从复制常用于负载均衡和数据备份。
87. 什么是MySQL的联合查询(JOIN)?
联合查询(JOIN)用于从多个表中组合数据。常见的JOIN类型包括:
INNER JOIN:返回两个表中匹配的数据。
LEFT JOIN:返回左表所有数据及右表匹配的数据。
RIGHT JOIN:返回右表所有数据及左表匹配的数据。
FULL JOIN:返回两个表中的所有数据。
88. 什么是MySQL的事务隔离级别?
MySQL支持四种事务隔离级别:
READ UNCOMMITTED:最低级别,允许读取未提交的数据。
READ COMMITTED:只允许读取已提交的数据。
REPEATABLE READ:保证在事务执行期间,所有读取的数据都是一致的。
SERIALIZABLE:最高级别,事务串行执行,避免任何并发操作。
89. MySQL中的自增(AUTO_INCREMENT)是什么?
AUTO_INCREMENT是MySQL中用于生成唯一标识符的属性,通常用于主键列。每当插入新记录时,MySQL会自动为该列生成一个递增的值,确保每条记录都有一个唯一的标识。
90. 如何优化MySQL查询性能?
优化MySQL查询性能的方法包括:
使用合适的索引来加速查询。
避免使用SELECT *,只选择需要的列。
使用EXPLAIN命令查看查询的执行计划,找出性能瓶颈。
对大型数据表进行分区或分表处理。
使用缓存技术来减少数据库的负载。
91. 什么是MySQL的数据库分区?
数据库分区是将一个大表分成多个较小的、独立的数据部分,以便于提高查询性能和管理效率。MySQL支持水平分区(按行)和垂直分区(按列)两种方式。
92. MySQL的触发器是什么?
触发器(Trigger)是MySQL中一种特殊的存储过程,用于在数据库表上执行插入、更新、删除操作时自动触发。触发器可以用于数据验证、日志记录等。
93. 什么是MySQL的存储过程?
存储过程是预编译的SQL语句集合,存储在数据库中,可以通过调用来执行。它可以提高应用程序的性能,因为减少了客户端和数据库之间的通信次数,并且可以将复杂的操作封装成单一的数据库调用。
94. MySQL中的外键约束如何影响性能?
外键约束会影响MySQL的性能,因为每次插入、更新或删除数据时,MySQL必须检查外键的参照完整性。这会导致额外的I/O操作和锁竞争,特别是在大型表中,可能会影响写操作的速度。
95. 什么是MySQL的临时表?
临时表是MySQL中只在当前会话或事务中存在的表,创建临时表不会影响其他用户。临时表通常用于存储中间结果,以便在查询过程中进行数据处理。
96. MySQL中的优化器如何选择执行计划?
MySQL的优化器会基于表的大小、索引的使用情况、统计信息等因素选择查询的执行计划。执行计划包括选择的索引、连接顺序等。开发者可以通过EXPLAIN命令查看查询的执行计划。
97. 如何通过JDBC执行MySQL存储过程?
通过JDBC执行存储过程,首先需要使用CallableStatement对象。示例代码如下:
CallableStatement stmt = conn.prepareCall("{call myProcedure(?, ?)}");
stmt.setInt(1, param1);
stmt.setString(2, param2);
stmt.execute();
98.如何在MySQL中创建和使用存储过程?
创建存储过程的语法如下:
DELIMITER //
CREATE PROCEDURE myProcedure(IN param1 INT, OUT param2 INT)
BEGIN
SELECT COUNT(*) INTO param2 FROM myTable WHERE myColumn = param1;
END //
DELIMITER ;
调用存储过程的语法如下:
CALL myProcedure(1, @result);
SELECT @result;
99.MySQL中的完整性约束有哪些?
MySQL的完整性约束用于确保数据的准确性和一致性。常见的约束有:
NOT NULL:确保列值不能为空。
UNIQUE:确保列值唯一。
PRIMARY KEY:唯一标识每一行记录。
FOREIGN KEY:确保数据的参照完整性。
CHECK:限制列值的范围(MySQL 8.0以后支持)。
DEFAULT:为列指定默认值。
100.MySQL中的JOIN操作有哪些优化方法?
优化MySQL的JOIN操作的常见方法包括:
使用合适的索引,特别是联接字段的索引。
避免使用JOIN连接太多表,尽量减少需要扫描的行数。
确保SQL查询尽量过滤早期表中的无关数据,减少数据量。
使用EXPLAIN分析查询的执行计划,确定是否使用了合适的索引。