Java并发编程是什么_新手入门核心知识解析

Java并发编程的核心是协调多线程对共享变量的读写顺序、可见时机和执行边界;i++非原子导致数据错乱,应优先用A

tomicInteger;volatile仅保证可见性与有序性,不保证原子性;线程状态单向流转,start()不可重复调用;JMM是默认前提,happens-before规则不可或缺。

Java并发编程不是“多开几个线程就完事”,而是**在共享内存模型下,有意识地协调多个线程对变量的读写顺序、可见时机和执行边界**。新手常以为只要用了 ThreadRunnable 就算会并发,结果一上线就出现数据错乱、偶发超时、CPU飙高——问题不在“会不会写线程”,而在“有没有守住临界区、有没有看清内存视图”。

为什么 i++ 在多线程里一定会出错?

这不是 Java 的 bug,是原子性缺失的必然结果:i++ 看似一条语句,实际被 JVM 拆成三步:getstatic iiaddputstatic i。两个线程同时读到 i = 5,各自加 1 后都写回 6,最终结果还是 6,而不是预期的 7。

  • 别用 synchronized 包裹所有 i++ —— 锁粒度太大会拖垮吞吐量
  • 优先用 AtomicInteger.incrementAndGet():底层靠 CPU 的 CAS 指令实现无锁原子更新
  • 如果必须用普通变量,且逻辑复杂(比如先判断再修改),才考虑 synchronizedReentrantLock

volatile 能不能代替 synchronized?

不能。它只解决**可见性 + 有序性**,不解决**原子性**。典型误用场景:

public class Counter {
    private volatile int count = 0;
    public void increment() {
        count++; // ❌ 仍非原子!volatile 不管这行怎么执行
    }
}
  • volatile 适合做状态标志:比如 private volatile boolean running = true;,配合 while(running) 控制循环退出
  • 它插入内存屏障,禁止编译器/CPU 对其读写重排序,但不会阻止其他线程在你读-改-写之间插一脚
  • 一旦涉及“读取→计算→写入”这类复合操作,volatile 就失效,必须升级为锁或原子类

线程启动后为啥调两次 start() 就抛 IllegalThreadStateException

因为 Java 线程状态是严格单向流转的:NEW → RUNNABLE → TERMINATED,中间不可逆。调用 start() 后,线程进入 RUNNABLE,再次调用就违反状态机规则。

  • 别用 thread.run() 试图“重启”线程——这只是普通方法调用,不创建新线程,也不改变状态
  • 需要重复执行逻辑?用循环 + 条件控制,或者扔进线程池(ExecutorService)反复提交 Runnable
  • 真正要复用的是线程资源,不是线程对象本身;Thread 实例是一次性的

最常被忽略的一点:**JMM(Java内存模型)不是可选知识,而是默认前提**。你写的每一行共享变量访问,都在和工作内存、主内存、缓存一致性打交道。不理解 happens-before 规则,就等于在没有地图的情况下调试分布式系统——现象诡异,修复随机,上线即回归。