OS
Java 线程状态
Java 没有 Ready 状态,线程状态有 6 种:
NEW 新建
RUNNABLE 可运行(包含 Ready + Running)
BLOCKED 阻塞(等待锁)
WAITING 等待(wait/join/park 等)
TIMED_WAITING 限时等待
TERMINATED 终止
好好学习,天天向上
Java 没有 Ready 状态,线程状态有 6 种:
NEW 新建
RUNNABLE 可运行(包含 Ready + Running)
BLOCKED 阻塞(等待锁)
WAITING 等待(wait/join/park 等)
TIMED_WAITING 限时等待
TERMINATED 终止
以线程 A 发起读取磁盘文件为例
当线程 A 执行到读取文件的代码时,它其实是没有权限直接控制底层硬件的,必须向操作系统老大哥(内核)求助。
在主线程中通过 new 关键字(例如 new Object() 或 new ReentrantLock())创建一个锁对象时,这个对象是被分配在 JVM 的**堆(Heap)**内存中的
在 Java 内存模型中,每个线程有自己私有的虚拟机栈(用于存储局部变量表、方法出口等),但堆内存是所有线程共享的。只要子线程能够拿到这个对象的内存地址(引用),它就可以访问这个对象。
当主线程启动子线程时,通常会将这个锁对象的引用(相当于这把锁在堆内存中的真实地址)通过某种方式传递给子线程:
Hashtable的底层数据结构主要是数组加上链表,数组是主体,链表是解决hash冲突存在的。
HashTable是线程安全的,实现方式是Hashtable的所有公共方法均采用synchronized关键字,当一个线程访问同步方法,另一个线程也访问的时候,就会陷入阻塞或者轮询的状态。
本质就是构建了一个存储了 Entry<?,?> 对象的数组,数据就存放在具体的 Entry 对象里,对应的索引根据 hash 来算
| 类 | 作用 |
|---|---|
| Semaphore | 限制线程的数量 |
| Exchanger | 两个线程交换数据 |
| CountDownLatch | 线程等待直到计数器减为 0 时开始工作 |
| CyclicBarrier | 作用跟 CountDownLatch 类似,但是可以重复使用 |
| Phaser | 增强的 CyclicBarrier |
常用的有五种
BlockingQueue<E>线程池是用来管理和复用线程的工具,它可以减少线程的创建和销毁开销
在 Java 中,ThreadPoolExecutor 是线程池的核心实现,它通过核心线程数、最大线程数、任务队列和拒绝策略来控制线程的创建和执行
任务执行流程如下:
任务提交 → 核心线程执行 → 任务队列缓存 → 非核心线程执行 → 拒绝策略处理
提交任务 → 核心线程是否已满?
├─ 未满 → 创建核心线程执行
└─ 已满 → 任务入队
├─ 队列未满 → 等待执行
└─ 队列已满 → 创建非核心线程
├─ 未达最大线程数 → 执行任务
└─ 已达最大线程数 → 执行拒绝策略
| 任务类型 | 线程状态 | CPU 使用 | 多线程效果 |
|---|---|---|---|
| CPU 密集型 | RUNNABLE | 高 | 可能更慢(切换开销) |
| IO 密集型 | WAITING | 低 | 更快(等待时间重叠) |
Future 是为了解决多线程执行任务并获取结果的问题
在传统的同步编程中,我们调用一个方法,必须死死等在这个方法那里,直到它执行完毕返回结果,代码才能继续往下走。
而 Future 代表的是一个异步计算的结果。
当你把一个耗时的任务(比如网络请求、复杂计算)扔给线程池(ExecutorService)去后台执行时,线程池会立刻塞给你一张“取餐小票”(也就是一个 Future 对象)。
拿到这张小票后,你的主线程不需要原地死等,可以立刻去干别的活儿。等你需要那个耗时任务的结果时,再拿着这张小票去兑换(调用 get() 方法)
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class OddEvenPrinterLock {
private int count = 1;
private final int MAX = 10;
// 主线程创建的锁对象
private final ReentrantLock lock = new ReentrantLock();
// 创建两个条件变量,相当于两个休息室
private final Condition oddCondition = lock.newCondition();
private final Condition evenCondition = lock.newCondition();
public void printOdd() {
while (count <= MAX) {
lock.lock(); // 尝试获取锁
try {
while (count % 2 == 0) {
oddCondition.await(); // 奇数线程去奇数休息室睡觉,并释放锁
}
if (count <= MAX) {
System.out.println(Thread.currentThread().getName() + " 打印奇数: " + count);
count++;
evenCondition.signal(); // 明确去偶数休息室叫醒偶数线程
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock(); // 切记在 finally 中释放锁
}
}
}
public void printEven() {
while (count <= MAX) {
lock.lock();
try {
while (count % 2 != 0) {
evenCondition.await(); // 偶数线程去偶数休息室睡觉,并释放锁
}
if (count <= MAX) {
System.out.println(Thread.currentThread().getName() + " 打印偶数: " + count);
count++;
oddCondition.signal(); // 明确去奇数休息室叫醒奇数线程
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
OddEvenPrinterLock printer = new OddEvenPrinterLock();
new Thread(printer::printOdd, "Thread-Odd").start();
new Thread(printer::printEven, "Thread-Even").start();
}
}