JUC 概述

📅 2026/6/20 3:32:41 👤 管理员 👁 次浏览
JUC 概述
并发并行串行并发宏观上同时进行微观上交替切换执行单个 CPU 核心靠快速切换任务并行同一时刻多个任务真正同时运行多个 CPU 核心每个核心独立跑一个任务串行同一时刻只做一件事做完一件再做下一件线程什么是线程一个程序运行时内部可以分成一个或多个线程线程是CPU 执行任务的最小单位创建线程的方式实现 RunnableclassMyRunnableimplementsRunnable{Overridepublicvoidrun(){System.out.println(Runnable 线程Thread.currentThread().getName());}}publicclassTest{publicstaticvoidmain(String[]args){MyRunnablernewMyRunnable();ThreadtnewThread(r);t.start();}}继承 ThreadclassMyThreadextendsThread{Overridepublicvoidrun(){System.out.println(线程运行Thread.currentThread().getName());}}publicclassTest{publicstaticvoidmain(String[]args){MyThreadtnewMyThread();t.start();// 启动线程}}实现 CallableclassMyCallableimplementsCallableInteger{OverridepublicIntegercall()throwsException{System.out.println(Callable 线程运行);return100;// 可以返回结果}}publicclassTest{publicstaticvoidmain(String[]args)throwsException{FutureTaskIntegertasknewFutureTask(newMyCallable());ThreadtnewThread(task);t.start();// 获取返回值Integerrestask.get();System.out.println(结果res);}}线程池创建publicclassTest{publicstaticvoidmain(String[]args){// 创建线程池ExecutorServicepoolExecutors.newFixedThreadPool(3);// 提交任务pool.submit(()-{System.out.println(线程池线程Thread.currentThread().getName());});pool.shutdown();// 关闭线程池}}线程的生命周期新建创建了一个线程对象但是没有调用 start() 方法就绪调用了 start()等着 CPU 分配时间片一旦拿到 CPU就开始执行 run()阻塞线程阻塞于锁等待主动无限期等别人唤醒例如wait() / join() / LockSupport.park()定时等待有时间限制的等待例如sleep(1000) / wait(1000) / join(1000)终止run() 执行完 / 异常退出状态的流转关系NEW → start() → RUNNABLE RUNNABLE ↓ 抢锁失败 BLOCKED → 拿到锁 → RUNNABLE RUNNABLE ↓ wait()/join() WAITING → notify()/notifyAll() → RUNNABLE RUNNABLE ↓ sleep(1000) TIMED_WAITING → 时间到 → RUNNABLE RUNNABLE → 执行完毕 → TERMINATED如何终止线程stop强制杀死线程已弃用interruptpublicclassTest{publicstaticvoidmain(String[]args)throwsInterruptedException{ThreadtnewThread(()-{try{while(!Thread.currentThread().isInterrupted()){System.out.println(运行中...);Thread.sleep(1000);}}catch(InterruptedExceptione){// 收到中断信号退出System.out.println(线程被中断终止);}});t.start();Thread.sleep(2000);t.interrupt();// 中断}}interrupt()、interrupted()、isInterrupted()的作用以及区别thread.interrupt()作用中断线程设置 interupted true类型实例方法效果如果线程正在运行仅设置中断标志不停止运行如果线程在 sleep()/wait()/join()会抛出 InterruptedException并清除中断标志不会强制停止线程只是通知thread.isInterrupted()作用查询是否被中断类型实例方法特点只读取不改变状态调用一次标记依然保留Thread.interrupted()作用查询 清除中断标记类型静态方法特点第一次调用返回 true第二次调用一定返回 false因为复位了只针对当前执行的线程例如在 main 线程中执行 t1.interrupted()其实查询的是 main 线程的 interupted 变量并复位synchronized锁升级无锁 → 偏向锁 → 轻量级锁 → 重量级锁单向升级不可降级只有释放锁后才会变回无锁无锁默认的无锁状态偏向锁jdk 15 默认取消偏向锁锁一直被同一个线程拿第一次抢锁CAS 把当前线程 ID 写入对象头之后再来只要线程 ID 匹配直接进不需要 CAS第二个线程来竞争时偏向锁被撤销 → 升级轻量级锁轻量级锁两个线程交替用锁无长时间阻塞参考线程在自己的栈帧创建 Lock Record把对象头复制到 Lock Record 中通过 CAS 把对象头换成指向自己 Lock Record 的指针成功拿到锁失败将锁升级为重量级锁然后进入 cxq 链表进行自旋自旋成功则获取锁自旋多次失败则会进入阻塞状态等待唤醒重量级锁monitor-enter每一个对象都会和一个监视器monitor关联, 监视器被占用时会被锁住, 其他线程无法来获取该监视器, 当JVM执行某个对象的 monitorenter(synchronized(obj)) 方法时, 会尝试去获取对象的监视器所有权, 过程如下:如果monitor 的进入数为 0, 则线程可以进入monitor, 并将 monitor 的进入数变为 1, 当前线程成为 monitor 的所有者如果线程已经拥有了 monitor 的所有权, 允许重入 monitor, 此时 monitor 的进入数 1如果其他线程已经占有了 monitor, 当前线程尝试获取 monitor 所有权时会被阻塞, 直到 monitor 的进入数为 0monitor-exit能执行monitorexit指令的线程一定是拥有monitor所有权的线程执行monitorexit指令后, monitor 的进入数 -1, 当进入数变为 0 后, 表示当前线程释放锁, 不再拥有 monitor 的所有权, 此时其他阻塞的线程可以去尝试获取monitor的所有权synchronized 执行时, 没有竞争到锁的线程会被挂起, 此时需要调用操作系统的park() 方法, 竞争到锁的线程会被 unpark() 唤醒