Java并发-线程基础
Java并发-线程基础
核心理论
1.1 线程生命周期
Java线程具有6种状态:新建(NEW)、运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、超时等待(TIMED_WAITING)和终止(TERMINATED)。线程状态之间的转换是并发编程的基础。
1.2 线程调度机制
Java线程调度采用抢占式调度模型,优先级高的线程优先执行。线程优先级范围为1-10,默认优先级为5。但线程优先级不能保证执行顺序,依赖于操作系统实现。
1.3 线程中断机制
线程中断是一种协作机制,通过调用interrupt()方法设置中断标志,线程可以通过isInterrupted()检查中断状态并做出响应。 InterruptedException异常会清除中断标志,需要注意正确处理。
代码实践
2.1 线程状态转换示例
public class ThreadStateExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000); // 进入TIMED_WAITING状态
synchronized (ThreadStateExample.class) {
ThreadStateExample.class.wait(); // 进入WAITING状态
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("线程状态1: " + thread.getState()); // NEW
thread.start();
System.out.println("线程状态2: " + thread.getState()); // RUNNABLE
Thread.sleep(100);
System.out.println("线程状态3: " + thread.getState()); // TIMED_WAITING
Thread.sleep(1000);
System.out.println("线程状态4: " + thread.getState()); // WAITING
synchronized (ThreadStateExample.class) {
ThreadStateExample.class.notify();
}
Thread.sleep(100);
System.out.println("线程状态5: " + thread.getState()); // TERMINATED
}
}
2.2 线程中断处理
public class ThreadInterruptExample {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("工作中...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// 重新设置中断标志
Thread.currentThread().interrupt();
break;
}
}
System.out.println("线程中断,退出工作");
});
worker.start();
Thread.sleep(2000);
worker.interrupt(); // 中断线程
}
}
设计思想
3.1 线程协作模式
- 生产者-消费者模式:通过共享队列实现线程间数据传递
- 读写分离模式:允许多个读线程同时访问,写线程互斥访问
- 线程池模式:管理线程生命周期,提高资源利用率
3.2 线程安全的单例模式
public class ThreadSafeSingleton {
private static volatile ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
public static ThreadSafeSingleton getInstance() {
if (instance == null) {
synchronized (ThreadSafeSingleton.class) {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}
避坑指南
4.1 线程启动与运行的区别
调用start()方法才会启动线程,使线程进入就绪状态;直接调用run()方法只是普通方法调用,不会创建新线程。
4.2 避免线程优先级反转
不要过度依赖线程优先级,高优先级线程可能被低优先级线程阻塞,导致优先级反转。可以通过设置适当的锁超时或使用Lock接口避免。
4.3 正确停止线程
避免使用stop()、suspend()和resume()方法,这些方法已被废弃。应使用中断机制或自定义标志位安全停止线程。
深度思考题
- 线程的sleep()和wait()方法有什么区别?
- 如何实现两个线程交替打印奇偶数?
- ThreadLocal的实现原理是什么?如何避免内存泄漏?
思考题回答:
sleep()是Thread类的静态方法,不会释放锁,指定时间后自动唤醒;wait()是Object类的方法,必须在同步块中调用,会释放锁,需要notify()或notifyAll()唤醒。
可以使用synchronized关键字、Lock接口或信号量实现。例如,使用两个线程共享一个计数器,通过wait()和notify()交替获取锁并打印数字。
ThreadLocal通过每个线程维护一个ThreadLocalMap来存储线程局部变量。内存泄漏风险源于ThreadLocalMap的Entry是弱引用,而Value是强引用。避免方法:使用完ThreadLocal后调用remove()方法清除值,或使用静态ThreadLocal变量。