中文在线
1. 锁
1.1 按获取方式:
- 悲观锁:假设总有线程冲突(如
synchronized、数据库行锁)。 - 乐观锁:假设不会有冲突,更新前校验版本(如
CAS + version)。
1.2 Java 常用锁:
| 锁类型 | 特点 |
|---|---|
synchronized | 内置锁,自动加解锁,重入 |
ReentrantLock | 可重入,灵活控制锁粒度 |
ReadWriteLock | 多读单写 |
StampedLock | 支持乐观读,适合高并发场景 |
SpinLock | 自旋等待,不阻塞线程 |
Semaphore | 信号量,限流控制 |
CountDownLatch | 多线程协作:等待计数归零 |
CyclicBarrier | 多线程协作:凑齐一批线程后执行 |
2. 线程的状态
线程生命周期中有 6 种状态:
| 状态 | 说明 |
|---|---|
| NEW | 新建线程对象,但未调用 start() |
| RUNNABLE | 可运行状态(可能正在运行或等待调度) |
| BLOCKED | 被阻塞,等待锁释放(如 synchronized 竞争) |
| WAITING | 无限期等待(如 Object.wait()) |
| TIMED_WAITING | 有时间限制的等待(如 sleep(), join(timeout)) |
| TERMINATED | 线程已结束 |
3. 线程会用到的关键字
✅ 常见的线程相关方法
-
start():启动一个新线程,调用此方法后,线程的状态变为 Runnable,由操作系统的线程调度器来调度执行。Thread t = new Thread();
t.start(); -
sleep(long millis):使当前线程休眠指定的毫秒数,释放 CPU 资源,让其他线程有机会执行。Thread.sleep(1000); // 让当前线程休眠 1 秒 -
join():当前线程等待指定线程执行完毕后再继续执行。常用于线程间的协作。thread.join(); // 当前线程等待该线程执行完成 -
yield():当前线程放弃 CPU 资源,进入就绪状态,让其他相同优先级的线程有机会执行,通常用于调度策略优化。Thread.yield(); -
interrupt():中断一个线程,通知线程停止当前执行。线程内部必须正确响应中断(通常通过抛出异常或检查中断状态)。thread.interrupt(); // 中断线程 -
isAlive():检查线程是否已启动并正在运行。thread.isAlive(); // 判断线程是否存活 -
setDaemon(boolean on):设置当前线程为守护线程,守护线程会在 JVM 退出时自动结束。thread.setDaemon(true); // 设置为守护线程 -
getId():获取线程的唯一 ID。long id = thread.getId(); // 获取线程 ID -
getState():获取线程的当前状态(如 NEW、RUNNABLE、WAITING、BLOCKED)。Thread.State state = thread.getState(); // 获取线程状态 -
currentThread():获取当前正在执行的线程的引用。Thread currentThread = Thread.currentThread(); // 获取当前线程
✅ 线程相关的关键字
-
synchronized:用于同步代码块或方法,保证线程安全。确保一个时刻只有一个线程能够执行被synchronized修饰的代码。synchronized (obj) {
// 只有一个线程可以执行这个代码块
} -
volatile:保证变量的可见性,确保一个线程修改了该变量,其他线程能立即看到修改后的值。它不保证原子性。private volatile boolean flag; -
final:用于定义不可修改的常量,常用于线程安全的对象设计。final int MAX_THREADS = 10; // 常量 -
ThreadLocal:为每个线程提供一个独立的变量副本,避免线程间共享数据,适合存储线程独立的数据(如用户会话信息等)。ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); -
wait():线程等待,释放对象锁,直到其他线程唤醒它。通常与notify()或notifyAll()一起使用。synchronized (obj) {
obj.wait(); // 当前线程释放锁并等待
} -
notify()/notifyAll():唤醒一个或所有等待该对象锁的线程。常与wait()一起使用,通常用于线程间的协调与通信。synchronized (obj) {
obj.notify(); // 唤醒一个线程
obj.notifyAll(); // 唤醒所有等待的线程
}
4. B树和B+树区别
| 对比项 | B树 | B+树(MySQL 索引结构) |
|---|---|---|
| 数据存储 | 所有节点都存数据 | 只有叶子节点存数据 |
| 查找效率 | 查找时可能在中间节点结束 | 查找一定在叶子节点,查询路径固定 |
| 区间查询 | 效率较低 | 叶子节点通过链表连接,支持范围查找高效 |
| 结构 | 多路搜索树 | 叶子节点链表 + 多路搜索树 |
5. 索引的底层数据结构
MySQL(InnoDB)的索引结构为 B+树,底层结构特点:
- 高度平衡的多路搜索树,一般高度为 2~3,性能稳定。
- 聚簇索引(主键索引):叶子节点存储整行数据。
- 辅助索引(二级索引):叶子节点存储主键值,需要回表。
优点:
- 范围查询性能高。
- 每次 I/O 读取一个数据页(通常 16KB),减少磁盘访问次数。
6. OAuth2登录
OAuth2 是一个授权协议,常用于第三方登录(如 GitHub、微信登录):
🌐 四种授权方式(常见是授权码模式):
🎯 授权码模式(适用于 Web 服务端):
- 用户访问客户端,点击“使用第三方登录”。
- 跳转到授权服务器(如 GitHub),授权登录。
- 授权后返回授权码(
code)。 - 客户端携带授权码换取 access_token。
- 使用 token 获取用户信息。
第三方登录使用的核心是 access_token + refresh_token。
7. token和cookie的区别
| 维度 | Token | Cookie |
|---|---|---|
| 存储位置 | 存储在浏览器本地(LocalStorage、SessionStorage) | 浏览器自动管理(内存或磁盘) |
| 携带方式 | 每次请求需前端手动放入 header | 自动随请求发送(如 Cookie Header) |
| 跨域支持 | 支持跨域访问 | 默认不支持跨域,需配置 withCredentials |
| 安全性 | 需防止 XSS 攻击 | 需防止 CSRF 攻击 |
| 适用场景 | 前后端分离,移动端 | 传统 Web 服务端渲染 |
实际项目中,经常使用 JWT(JSON Web Token) 存储用户身份信息,结合
Bearer Token使用。