当前位置: 首页 > news >正文

Java多线程基础详解:从实现到线程安全

一、Thread与Runnable实现方式对比

1.1 继承Thread类实现多线程

class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread running: " + Thread.currentThread().getName());}
}public class ThreadDemo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.start();t2.start();}
}

特点

  • 直接继承Thread类并重写run()
  • 每个线程对象独立运行,资源共享需额外处理
  • 受单继承限制,扩展性较弱

1.2 实现Runnable接口方式

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable running: " + Thread.currentThread().getName());}
}public class RunnableDemo {public static void main(String[] args) {MyRunnable task = new MyRunnable();new Thread(task, "Thread-1").start();new Thread(task, "Thread-2").start();}
}

优势

  • 避免单继承限制,保持类设计灵活性
  • 同一任务对象可被多个线程共享
  • 更符合"组合优于继承"的设计原则

1.3 关键对比

特性Thread类Runnable接口
实现方式继承类实现接口
资源共享需独立实例可共享实例
锁机制对象锁需显式同步
线程池适配需转换为Runnable直接适配

二、sleep()与wait()深度解析

2.1 核心区别对比

特性sleep()wait()
方法归属Thread类(静态方法)Object类(实例方法)
锁行为不释放锁释放对象锁
唤醒机制时间到期自动唤醒需notify()/notifyAll()
使用场景定时任务/延迟操作线程协作/条件等待
异常处理抛出InterruptedException同上

2.2 典型使用场景

sleep()示例(定时任务)

// 每秒执行一次任务
while (true) {processTask();try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}
}

wait()示例(生产者-消费者)

class SharedQueue {private final List<Object> queue = new ArrayList<>();public synchronized void put(Object obj) {while (queue.size() == MAX_SIZE) {try {wait(); // 队列满时等待} catch (InterruptedException e) {}}queue.add(obj);notifyAll();}public synchronized Object take() {while (queue.isEmpty()) {try {wait(); // 队列空时等待} catch (InterruptedException e) {}}Object obj = queue.remove(0);notifyAll();return obj;}
}

2.3 注意事项

  1. wait()必须在同步代码块内调用
  2. 优先使用notifyAll()而非notify()避免死锁
  3. sleep()时间精度受系统调度影响
  4. 避免在循环外使用wait()

三、线程安全经典案例分析

3.1 非原子操作引发的问题

class Counter {private int count = 0;public void increment() {count++; // 非原子操作(load→add→store)}public int getCount() {return count;}
}public class UnsafeDemo {public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 10000; i++) {counter.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 10000; i++) {counter.increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println("Final count: " + counter.getCount()); // 可能小于20000}
}

3.2 解决方案对比

同步方法

public synchronized void increment() {count++;
}

同步代码块

public void increment() {synchronized (this) {count++;}
}

原子类

import java.util.concurrent.atomic.AtomicInteger;class SafeCounter {private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet();}public int getCount() {return count.get();}
}

3.3 性能优化策略

  1. 缩小同步范围
// 不推荐
public synchronized void process() {// 非共享操作...count++;
}// 推荐
public void process() {// 非共享操作...synchronized (this) {count++;}
}
  1. 锁分离技术
class AdvancedCounter {private final Object readLock = new Object();private final Object writeLock = new Object();private int count = 0;public void increment() {synchronized (writeLock) {count++;}}public int getCount() {synchronized (readLock) {return count;}}
}
  1. 使用并发容器
// 替代synchronizedList
List<String> list = new CopyOnWriteArrayList<>();// 替代synchronizedMap
Map<String, Integer> map = new ConcurrentHashMap<>();

四、多线程最佳实践

  1. 优先使用Runnable接口实现多线程
  2. 尽可能缩小同步代码块范围
  3. 优先使用并发工具类替代synchronized
  4. 避免在循环外使用wait()/notify()
  5. 合理使用线程池管理线程生命周期
  6. 对竞争资源使用原子类操作
  7. 始终考虑线程安全问题,即使看似安全的只读操作

通过本文的系统讲解,相信读者已经掌握了Java多线程编程的核心概念和实战技巧。在实际开发中,建议结合JUC包中的高级并发工具(如Lock、Semaphore、CountDownLatch等)来构建更高效稳定的多线程应用。

http://www.lryc.cn/news/593665.html

相关文章:

  • 6. 装饰器模式
  • ROS2 视频采集节点实现
  • Redis常见线上问题
  • 基于LSTM的时间序列到时间序列的回归模拟
  • Keepalived 监听服务切换与运维指南
  • C study notes[1]
  • C语言:20250719笔记
  • CentOS 清理技巧
  • 第二次总结(xss、js原型链)
  • 在开发板tmp目录下传输文件很快的原因和注意事项:重启开发板会清空tmp文件夹,记得复制文件到其他地方命令如下(cp 文件所在路径 文件要复制到的路径—)
  • 【Linux】重生之从零开始学习运维之Nginx之server小实践
  • 定时器中BDTR死区时间和刹车功能配置
  • AWS Partner: Accreditation (Technical)
  • Qt Graphs 模块拟取代 charts 和 data visualization还有很长的路要走
  • SPARKLE:深度剖析强化学习如何提升语言模型推理能力
  • stm32继电器使用方法
  • 【RK3576】【Android14】UART开发调试
  • 从零开始学Tailwind CSS : 颜色配置原理与实践
  • EasyExcel使用
  • 创建套接字并bind的详细过程
  • 深度学习-线性神经网络
  • 深度学习Depth Anything V2神经网络实现单目深度估计系统源码
  • 短视频矩阵的未来前景:机遇无限,挑战并存
  • Maven常用知识总结
  • 代码随想录算法训练营第二十天|回溯part02
  • 电阻耐压参数学习总结
  • 动态规划——数位DP经典题目
  • 【深度学习-Day 38】破解深度网络退化之谜:残差网络(ResNet)核心原理与实战
  • 从0到1搭建一个Rag引擎(ollama+Qwen3)
  • 实现el-select下拉框,下拉时加载数据