所谓教条,就是生搬硬套,以开放的心态接受新概念,理解上下文,注重实践和经验。
Java的并发模型是传统的基于内存共享的并发模型
如何查看线程的状态(Jstack)
线程的生命周期
将线程比喻成人,是一种很好的理解方式,比喻成人的生老病死,人与人之间的协作,等等。

4. 线程安全问题 (原子性 可见性 有序性)
原子性 实例
| public class Demo extends Thread { |
| private static int num=100000; |
| @Override |
| public void run() { |
| addNumber(); |
| } |
| |
| [synchronized] static public void addNumber() { |
| for (int i1 = 0; i1 < 5000; i1++) { |
| num--; |
| } |
| } |
| public static void main(String[] args) throws InterruptedException { |
| Thread[] threads = new Thread[20]; |
| for (int i = 0; i < threads.length; i++) { |
| new Thread(new Demo()).start(); |
| } |
| System.out.println( "结果:" + num); |
| } |
| } |
可见性 实例
| public class Demo { |
| |
| static volatile boolean flag =true; |
| public static void main(String[] args) throws InterruptedException { |
| new Thread(()->{ |
| int i =0; |
| while (flag) { |
| i++; |
| } |
| } |
| ).start(); |
| Thread.sleep(1000); |
| flag=false; |
| } |
有序性 实例
CPU 的编译,指令优化会破坏语句的执行顺序
synchronized 对象锁用法
-
同步方法
-
同步静态方法
| synchronized static (this) { |
| } |
-
同步方法块
synchronized 对象锁实例
| public class Demo3 implements Runnable{ |
| static int num; |
| synchronized static void add() { |
| for (int i = 0; i < 20000; i++) { |
| num++; |
| } |
| } |
| @Override |
| public void run() { |
| add(); |
| } |
| public static void main(String[] args) throws InterruptedException { |
| |
| for (int i = 0; i < 10; i++) { |
| Thread thread = new Thread(new Demo3()); |
| thread.start(); |
| } |
| Thread.sleep(2000); |
| System.out.println(num); |
| |
| } |
| } |
线程的基本操作 (线程通信)
线程的三种创建方式- Callable 接口实现
| public class CallableDemo implements Callable { |
| @Override |
| public Object call() throws Exception { |
| return null; |
| } |
| @Override |
| public void run() { |
| System.out.println("runnable 实现的线程"); |
| } |
| public static void main(String[] args) throws InterruptedException, ExecutionException { |
| ExecutorService executor = Executors.newFixedThreadPool(2); |
| Callable callable = new CallableDemo(); |
| Future<String> t1 = executor.submit(callable); |
| String s = t1.get(); |
| System.out.println("开始消费"); |
| } |
| } |
| |
线程的三种创建方式- 继承Thread 类
| public class Threaddemo extends Thread { |
| @Override |
| public void run() { |
| System.out.println("hello"); |
| } |
| |
| public static void main(String[] args) { |
| new Threaddemo().start(); |
| } |
| } |
线程的三种创建方式- 实现runnable 接口
| public class CallableDemo implements Runnable { |
| @Override |
| public void run() { |
| System.out.println("runnable 实现的线程"); |
| } |
| public static void main(String[] args) { |
| Thread thread = new Thread(new CallableDemo()); |
| thread.start(); |
| } |
| } |
join阻塞主线程实例
| public class Demo3 implements Runnable{ |
| static int num; |
| @Override |
| public void run() { |
| for (int i = 0; i < 20000; i++) { |
| num++; |
| } |
| } |
| |
| public static void main(String[] args) throws InterruptedException { |
| for (int i = 0; i < 10; i++) { |
| Thread thread = new Thread(new Demo3()); |
| thread.start(); |
| |
| } |
| Thread.sleep(2000); |
| System.out.println(num); |
| |
| } |
| } |
| 1. join 阻塞的是主线程 |
| 2. 因为多线程的执行是异步的,如果写代码时候,如果不阻塞主线程,有时候数据操作的值输出并不完整 |
wait notify 实例
main
| public class Demo { |
| public static void main(String[] args) throws InterruptedException { |
| Queue<Integer> queue = new LinkedList<>(); |
| new Thread(new Puroduce(queue,100)).start(); |
| new Thread(new Consumer(queue,100)).start(); |
| |
| Thread.sleep(1000); |
| |
| |
| |
| |
| } |
| } |
join 实例
interrupter 实例
yeild 实例
生产者
| public class Puroduce implements Runnable { |
| Queue<Integer> queue; |
| private int size; |
| |
| public Puroduce(Queue<Integer> queue, int size) { |
| this.queue = queue; |
| this.size = size; |
| } |
| |
| private void produce() throws Exception { |
| int i = 0; |
| while (true) { |
| i++; |
| synchronized (queue) { |
| while (queue.size() == size) { |
| System.out.println("已经满了"); |
| queue.wait(); |
| } |
| queue.add(i); |
| System.out.println("生产者开始生产: " + i); |
| Thread.sleep(100); |
| queue.notifyAll(); |
| } |
| } |
| } |
| @Override |
| public void run() { |
| try { |
| produce(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
消费者
| public class Consumer implements Runnable { |
| Queue<Integer> queue; |
| private int size = 0; |
| public Consumer(Queue<Integer> queue, int size) { |
| this.queue = queue; |
| this.size = size; |
| } |
| private void sonsume() throws Exception { |
| int i = 0; |
| synchronized (queue) { |
| while (true) { |
| i++; |
| while (queue.isEmpty()){ |
| System.out.println("已经消费完了"); |
| queue.wait(); |
| } |
| Integer remove = queue.remove(); |
| System.out.println("消费者开始消费: " + remove); |
| Thread.sleep(100); |
| queue.notifyAll(); |
| } |
| } |
| } |
| @Override |
| public void run() { |
| try { |
| sonsume(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
总结
| synchronized 对象锁 锁住同样一个对象 让两个线程相互通信 |
JUC 包和AQS
什么是AQS
AQS(AbstractQueuedSynchronizer)是Java中的一个用于构建锁和同步器的框架,它是java.util.concurrent包中的核心组件之一。Doug Lea开发了AQS,它为实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关的同步器(信号量、事件等)提供了一个基础框架。
AQS利用了一个整型的状态(state)变量来表示同步状态,通过内部的方法来改变这个状态,并且提供了一种高效的方式来管理线程的阻塞和唤醒。它是许多并发工具的基础,例如ReentrantLock、CountDownLatch、Semaphore、ReentrantReadWriteLock等。
AQS的工作原理:
1.状态(State): AQS使用一个整数(state)来表示同步状态,根据具体的同步器的需求,这个状态可以代表不同的意义。例如,在ReentrantLock中,状态为0表示未锁定状态,而大于0表示锁定状态,并且计数表示重入的次数。
2.等待队列: 当线程尝试获取同步状态失败时,AQS会将该线程包装成一个节点(Node)加入到等待队列中。等待队列是一个类型为Node的双向链表,用来管理所有等待获取同步状态的线程。
3.获取和释放同步状态: AQS定义了两种资源获取的方式:独占和共享。独占方式下,一个时间点只能有一个线程获取到资源。共享方式下,允许多个线程同时获取到资源。具体的同步器可以根据需求选择实现这两种方式中的一种或两种。
AQS的重要方法:
- protected boolean tryAcquire(int arg):尝试获取资源,成功则返回true,失败则返回false。
- protected boolean tryRelease(int arg):尝试释放资源,成功则返回true,失败则返回false。
- protected int tryAcquireShared(int arg):尝试获取共享资源。
- protected boolean tryReleaseShared(int arg):尝试释放共享资源。
- public final void acquire(int arg)、public final void acquireShared(int arg):调用这些方法的线程将会在获取不到资源时,被加入到等待队列中,并在条件满足时被唤醒。
AQS通过内部维护的等待队列来管理所有竞争资源的线程,当一个线程获取资源时,AQS会根据资源的状态和获取模式(独占/共享)来决定是否需要阻塞线程,当资源被释放时,会从等待队列中唤醒一个或多个线程来尝试获取资源。这个机制是构建锁和其他同步器的基础,使得开发者可以较为容易地实现安全的并发控制。
重入锁ReentrantLock
| public class Demo3 implements Runnable{ |
| static int num; |
| static ReentrantLock lock = new ReentrantLock(); |
| |
| void add() { |
| lock.lock(); |
| for (int i = 0; i < 20000; i++) { |
| num++; |
| } |
| lock.unlock(); |
| } |
| |
| @Override |
| public void run() { |
| add(); |
| } |
| |
| public static void main(String[] args) throws InterruptedException { |
| |
| for (int i = 0; i < 10; i++) { |
| Thread thread = new Thread(new Demo3()); |
| thread.start(); |
| } |
| Thread.sleep(2000); |
| System.out.println(num); |
| |
| } |
| } |
| 重入锁的意思,就是一个对象在访问多个争用资源时候,拿到了相同的锁之后,就不用再去获得锁 |
| |
| 如果是共享锁,对象在访问多个争用资源的时候,获得了一个锁,别的对象没有锁不能访问该资源,而访问第二个争用资源时,又没有先释放锁,造成了死锁现象。 |
java 中如何使用线程池
线程池的类别

线程池的使用方法 Executors.newFixedThreadPool 实例
| public class Demo4 implements Runnable{ |
| static int num; |
| synchronized static void add() { |
| for (int i = 0; i < 20000; i++) { |
| num++; |
| } |
| } |
| @Override |
| public void run() { |
| add(); |
| System.out.println(Thread.currentThread().getName()); |
| } |
| |
| public static void main(String[] args) throws InterruptedException { |
| ExecutorService executorService = Executors.newFixedThreadPool(2); |
| for (int i = 0; i < 3; i++) { |
| executorService.execute(new Demo4()); |
| } |
| Thread.sleep(200); |
| System.out.println("最终结果: "+ num); |
| executorService.shutdownNow(); |
| } |
| } |
java 的对象结构
mark Word 结构信息
JOL 查看对象布局
锁升级
JMM 内存模型
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具