Java--多线程--04

以下是针对线程状态的极其详细讲解。本篇将按照线程的六种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)逐一展开,每个状态包括定义、原因、代码案例、练习,以及易错点、混淆点和容易搞错的点。

线程状态概述

线程是程序执行的最小单位,其状态反映了线程在生命周期中的行为。理解这些状态对调试并发问题、避免死锁和提高性能至关重要。Java中,线程状态通过Thread.State枚举表示,包括:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。每个状态都有特定触发条件和行为,下面我们逐一深入讲解。


1. NEW(新建)

定义与原因

NEW状态表示线程对象已被创建(例如,通过new Thread()),但尚未调用start()方法启动。此时,线程只是内存中的一个对象,没有分配系统资源(如CPU时间片),不会执行run()方法。只有调用start()后,线程才进入RUNNABLE状态。

代码案例
public class NewStateExample { public static void main(String[] args) { // 创建线程对象,但未调用start() Thread thread = new Thread(() -> { System.out.println("线程运行中"); }); // 打印线程状态:应为 NEW System.out.println("线程状态: " + thread.getState()); // 输出: NEW } } 

运行此代码,线程状态为NEW,因为start()未被调用。

练习

每个练习旨在加深理解,请先尝试解答,再参考解释。

练习5:资源占用问题
在NEW状态下,线程是否占用系统资源(如CPU或内存)?编写代码创建1000个NEW线程,观察内存使用(可用Runtime.getRuntime().totalMemory())。

public class ResourceTest { public static void main(String[] args) { for (int i = 0; i < 1000; i++) { new Thread(() -> {}); // 只创建,不start } System.out.println("内存占用: " + Runtime.getRuntime().totalMemory()); } } 

解释:NEW线程占用内存(对象开销),但不占用CPU。易错点:误以为NEW线程无开销,导致内存泄漏。

练习4:错误场景分析
假设代码中多次调用start()方法(例如:thread.start(); thread.start();)。会发生什么?状态如何变化?

Thread thread = new Thread(() -> {}); thread.start(); thread.start(); // 第二次调用start() 

解释:抛出IllegalThreadStateException,因为线程不能重复启动。状态在第一次start()后变为RUNNABLE或TERMINATED,但不会回到NEW。易错点:忽略线程状态的生命周期,以为可以重复启动。

练习3:状态转换模拟
创建一个线程对象,先打印状态(应为NEW),然后调用start(),再打印状态。观察变化。

Thread thread = new Thread(() -> {}); System.out.println("start前状态: " + thread.getState()); // NEW thread.start(); System.out.println("start后状态: " + thread.getState()); // 可能为RUNNABLE 

解释:调用start()后状态变为RUNNABLE。易错点:在多线程环境中,状态打印可能受调度影响,不一定是即时变化。

练习2:方法调用影响
在NEW状态下,线程能否调用run()方法?如果可以,调用后状态会变吗?编写代码测试。

Thread thread = new Thread(() -> { System.out.println("run()方法执行"); }); thread.run(); // 直接调用run() System.out.println("状态: " + thread.getState()); 

解释:直接调用run()不会改变状态(仍为NEW),因为它只是普通方法调用,而非启动线程。易错点:混淆run()start(),以为run()能启动线程。

练习1:基础状态检查
编写代码创建两个线程对象,但不调用start()。打印它们的线程状态。确认状态是否为NEW。

// 示例代码框架 Thread t1 = new Thread(() -> {}); Thread t2 = new Thread(() -> {}); System.out.println("t1状态: " + t1.getState()); System.out.println("t2状态: " + t2.getState()); 

解释:状态应为NEW。易错点:误以为线程创建后自动启动。

易错点与混淆点
  • 易错点:NEW状态容易被忽略,因为线程不执行任何任务。开发者可能在创建线程后忘记调用start(),导致程序逻辑错误。
  • 混淆点:NEW状态与“未初始化”混淆。NEW线程对象已初始化,但未激活。与RUNNABLE混淆,因为两者都涉及线程对象存在。
  • 容易搞错的点:直接调用run()方法不会改变状态,它只是同步执行代码块,而非启动新线程。线程启动必须通过start()

2. RUNNABLE(可运行)

定义与原因

RUNNABLE状态表示线程已启动(调用start()),正在运行或等待CPU时间片。在Java中,RUNNABLE统一表示就绪(Ready)和运行(Running)状态:就绪时线程等待调度,运行时占用CPU执行。操作系统层面,就绪和运行是分开的,但Java API只暴露RUNNABLE。线程可通过yield()让出CPU,但状态不变。

代码案例
public class RunnableStateExample { public static void main(String[] args) { Thread thread = new Thread(() -> { while (true) { // 模拟运行 } }); thread.start(); System.out.println("线程状态: " + thread.getState()); // 输出: RUNNABLE } } 

线程启动后进入RUNNABLE状态,可能在运行或就绪。

练习

练习5:状态与性能
编写代码,测量线程在RUNNABLE状态下的CPU占用(可用ThreadMXBean)。观察就绪和运行的区别。

import java.lang.management.ThreadMXBean; import java.lang.management.ManagementFactory; public class CpuUsage { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { while(true) {} }); thread.start(); ThreadMXBean bean = ManagementFactory.getThreadMXBean(); long cpuTime = bean.getThreadCpuTime(thread.getId()); System.out.println("CPU时间: " + cpuTime); // 非零表示运行过 System.out.println("状态: " + thread.getState()); // RUNNABLE } } 

解释:RUNNABLE状态不区分就绪和运行,但CPU时间非零表示线程曾运行。易错点:混淆状态和实际CPU占用。

练习4:多线程并发
启动10个线程,每个打印自己的状态。所有状态应为RUNNABLE吗?

for (int i = 0; i < 10; i++) { new Thread(() -> { System.out.println("状态: " + Thread.currentThread().getState()); }).start(); } 

解释:输出可能显示RUNNABLE,但受调度影响,打印时线程可能在运行或就绪。易错点:在多核CPU上,多个线程可同时运行,状态打印可能不一致。

练习3:yield()方法影响
在线程中调用Thread.yield(),打印状态。状态会变吗?

Thread thread = new Thread(() -> { while (true) { Thread.yield(); // 让出CPU } }); thread.start(); System.out.println("状态: " + thread.getState()); // RUNNABLE 

解释:状态仍为RUNNABLE,yield()只是提示调度器让出CPU,不改变状态。易错点:误以为yield()使线程进入WAITING。

练习2:CPU竞争模拟
创建两个高优先级线程,竞争CPU。打印状态,观察调度。

Thread t1 = new Thread(() -> { while(true) {} }); Thread t2 = new Thread(() -> { while(true) {} }); t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MAX_PRIORITY); t1.start(); t2.start(); System.out.println("t1状态: " + t1.getState()); // RUNNABLE System.out.println("t2状态: " + t2.getState()); // RUNNABLE 

解释:两者均为RUNNABLE,但操作系统可能切换运行状态。易错点:以为优先级高的线程总在运行状态。

练习1:状态打印时机
启动一个线程,在循环中打印状态。观察状态是否总为RUNNABLE。

Thread thread = new Thread(() -> { while (true) { /* 空循环 */ } }); thread.start(); for (int i = 0; i < 5; i++) { System.out.println("状态: " + thread.getState()); // 应为RUNNABLE Thread.sleep(100); // 主线程睡眠,让子线程运行 } 

解释:状态始终为RUNNABLE。易错点:误以为在循环中状态会变化,但RUNNABLE涵盖就绪和运行。

易错点与混淆点
  • 易错点:RUNNABLE状态在Java中统一表示,但开发者可能误以为线程总在运行,忽略就绪状态。导致性能优化时忽略调度开销。
  • 混淆点:与BLOCKED混淆,因为两者都可能“等待”,但RUNNABLE是主动等待CPU,BLOCKED是被动等待锁。
  • 容易搞错的点:线程在I/O操作(如文件读写)时状态仍为RUNNABLE,因为I/O在Java中可能不阻塞线程(使用NIO时)。操作系统层可能阻塞,但Java状态不变。

3. BLOCKED(阻塞)

定义与原因

BLOCKED状态表示线程因等待监视器锁(如synchronized关键字)而阻塞。只有当线程试图进入synchronized代码块或方法,但锁被其他线程持有时,才进入此状态。一旦锁释放,线程自动转为RUNNABLE。注意:BLOCKED仅针对synchronized锁,不适用于其他锁机制(如ReentrantLock)。

代码案例
public class BlockedStateExample { public static final Object lock = new Object(); public static void main(String[] args) { Thread t1 = new Thread(() -> { synchronized (lock) { while (true) {} // 持有锁不释放 } }); Thread t2 = new Thread(() -> { synchronized (lock) { // 等待锁 System.out.println("t2获得锁"); } }); t1.start(); t2.start(); System.out.println("t2状态: " + t2.getState()); // 可能为BLOCKED } } 

t2在等待锁时进入BLOCKED状态。

练习

练习5:非synchronized锁
使用ReentrantLock代替synchronized,线程在等待锁时状态是什么?

import java.util.concurrent.locks.ReentrantLock; ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(() -> { lock.lock(); // 持有锁 while (true) {} }); Thread t2 = new Thread(() -> { lock.lock(); // 等待锁 }); t1.start(); t2.start(); System.out.println("t2状态: " + t2.getState()); // WAITING, 非BLOCKED 

解释ReentrantLock的等待使线程进入WAITING状态(通过LockSupport.park()),而非BLOCKED。易错点:以为所有锁机制都导致BLOCKED状态。

练习4:死锁检测
创建死锁场景:两个线程互相等待锁。打印状态,识别BLOCKED线程。

Object lock1 = new Object(); Object lock2 = new Object(); Thread t1 = new Thread(() -> { synchronized (lock1) { synchronized (lock2) {} // 等待lock2 } }); Thread t2 = new Thread(() -> { synchronized (lock2) { synchronized (lock1) {} // 等待lock1 } }); t1.start(); t2.start(); Thread.sleep(1000); System.out.println("t1状态: " + t1.getState()); // BLOCKED System.out.println("t2状态: " + t2.getState()); // BLOCKED 

解释:两者均BLOCKED,形成死锁。易错点:死锁时线程永久BLOCKED,需外部干预。

练习3:BLOCKED vs WAITING
使用wait()方法,线程状态是什么?编写代码对比。

Object lock = new Object(); Thread t1 = new Thread(() -> { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) {} // 调用wait() } }); t1.start(); Thread.sleep(100); System.out.println("t1状态: " + t1.getState()); // WAITING, not BLOCKED 

解释:调用wait()进入WAITING状态,而非BLOCKED。易错点:混淆BLOCKED(锁竞争)和WAITING(主动等待)。

练习2:错误锁释放
线程在BLOCKED状态下,如何被唤醒?修改代码,让t1释放锁后观察t2状态变化。

// 同上代码,但t1 sleep后释放锁 // t2状态在t1释放后变为RUNNABLE 

解释:锁释放后,t2自动转为RUNNABLE。易错点:误以为需要显式唤醒(如notify()),但BLOCKED是自动恢复。

练习1:锁竞争
创建两个线程竞争同一锁。打印等待线程的状态。

Object lock = new Object(); Thread t1 = new Thread(() -> { synchronized (lock) { try { Thread.sleep(1000); } catch (InterruptedException e) {} } }); Thread t2 = new Thread(() -> { synchronized (lock) { // 等待锁 } }); t1.start(); t2.start(); Thread.sleep(100); // 让t1先运行 System.out.println("t2状态: " + t2.getState()); // BLOCKED 

解释:t2在等待锁时状态为BLOCKED。易错点:未确保t1先获得锁,导致状态打印错误。

易错点与混淆点
  • 易错点:BLOCKED状态只发生在synchronized锁竞争时。开发者可能在其他等待场景(如I/O)误判为BLOCKED。
  • 混淆点:与WAITING状态混淆,因为两者都涉及“等待”,但BLOCKED是自动恢复的锁等待,WAITING需要显式唤醒。
  • 容易搞错的点:在ReentrantLockCondition上等待时,状态是WAITING或TIMED_WAITING,不是BLOCKED。忽略这点会导致调试错误。

4. WAITING(等待)

定义与原因

WAITING状态表示线程因调用无期限等待方法而暂停,例如Object.wait()Thread.join()LockSupport.park()。线程进入此状态后,不会消耗CPU资源,必须由其他线程显式唤醒(如notify()unpark())。WAITING常用于线程间协调,如生产者-消费者模型。

代码案例
public class WaitingStateExample { public static final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { synchronized (lock) { try { lock.wait(); // 进入WAITING } catch (InterruptedException e) {} } }); thread.start(); Thread.sleep(100); // 确保thread进入wait System.out.println("线程状态: " + thread.getState()); // WAITING } } 

线程调用wait()后进入WAITING状态。

练习

练习5:LockSupport.park()
使用LockSupport.park()使线程进入WAITING。如何唤醒?

Thread thread = new Thread(() -> { LockSupport.park(); // 进入WAITING }); thread.start(); Thread.sleep(100); System.out.println("状态: " + thread.getState()); // WAITING LockSupport.unpark(thread); // 唤醒 

解释park()进入WAITING,unpark()唤醒。易错点:unpark()可在park()前调用,防止永久等待。

练习4:多线程协调
实现生产者-消费者模型,生产者wait()当缓冲区满。打印状态确认WAITING。

import java.util.Queue; import java.util.LinkedList; Queue<Integer> buffer = new LinkedList<>(); int maxSize = 1; Object lock = new Object(); Thread producer = new Thread(() -> { synchronized (lock) { while (buffer.size() == maxSize) { try { lock.wait(); } catch (InterruptedException e) {} // WAITING } buffer.add(1); lock.notify(); } }); producer.start(); // 类似创建consumer线程 

解释:当缓冲区满时,生产者进入WAITING。易错点:未在循环中检查条件(虚假唤醒问题)。

练习3:永久等待风险
编写代码,线程wait()但无唤醒逻辑。状态会变吗?如何避免死锁?

Object lock = new Object(); Thread t = new Thread(() -> { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) {} } }); t.start(); // 无唤醒代码 Thread.sleep(2000); System.out.println("状态: " + t.getState()); // 仍为WAITING 

解释:状态永久WAITING,导致线程泄漏。易错点:忘记设计唤醒机制。

练习2:join()方法
主线程调用子线程的join(),状态是什么?

Thread child = new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) {} }); child.start(); child.join(); // 主线程调用join() // 在主线程中打印自身状态? System.out.println("主线程状态: " + Thread.currentThread().getState()); // RUNNABLE 

解释join()使调用线程(主线程)进入WAITING状态,等待子线程结束。但打印自身状态时为RUNNABLE,因为join()内部实现使用WAITING。易错点:误以为join()改变的是子线程状态。

练习1:wait()方法使用
线程调用wait()后,状态如何?编写代码唤醒它,观察状态变化。

Object lock = new Object(); Thread t = new Thread(() -> { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) {} System.out.println("唤醒后"); } }); t.start(); Thread.sleep(100); System.out.println("状态: " + t.getState()); // WAITING synchronized (lock) { lock.notify(); // 唤醒 } Thread.sleep(100); System.out.println("状态: " + t.getState()); // RUNNABLE或TERMINATED 

解释:唤醒后状态变为RUNNABLE。易错点:忘记在同步块内调用notify(),导致唤醒失败。

易错点与混淆点
  • 易错点:WAITING状态需要显式唤醒,开发者可能忘记调用notify()unpark(),导致线程永久挂起。
  • 混淆点:与BLOCKED混淆,因为两者都“等待”,但WAITING是主动调用等待方法,BLOCKED是锁竞争被动等待。
  • 容易搞错的点Thread.join()使调用线程进入WAITING,而非被join的线程。忽略这点会导致状态判断错误。

5. TIMED_WAITING(计时等待)

定义与原因

TIMED_WAITING状态表示线程因调用有时间限制的等待方法而暂停,例如Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)。线程在指定时间后自动唤醒(或提前被中断),无需显式唤醒。常用于定时任务或超时控制。

代码案例
public class TimedWaitingStateExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { try { Thread.sleep(1000); // 进入TIMED_WAITING } catch (InterruptedException e) {} }); thread.start(); Thread.sleep(100); // 确保thread进入sleep System.out.println("线程状态: " + thread.getState()); // TIMED_WAITING } } 

线程sleep()时进入TIMED_WAITING状态。

练习

练习5:定时任务模拟
创建线程每秒执行任务,使用sleep(1000)。打印状态确认TIMED_WAITING。

Thread timer = new Thread(() -> { while (true) { System.out.println("任务执行"); try { Thread.sleep(1000); } catch (InterruptedException e) {} } }); timer.start(); Thread.sleep(1500); System.out.println("状态: " + timer.getState()); // TIMED_WAITING (在sleep期间) 

解释:在sleep()期间状态为TIMED_WAITING。易错点:循环中使用sleep()可能导致精度问题。

练习4:中断处理
线程在TIMED_WAITING时被中断(interrupt()),状态如何?编写代码测试。

Thread t = new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("中断捕获"); } }); t.start(); Thread.sleep(100); t.interrupt(); // 中断 Thread.sleep(100); System.out.println("状态: " + t.getState()); // RUNNABLE或TERMINATED 

解释:中断后线程唤醒,状态变为RUNNABLE。易错点:未处理InterruptedException,导致行为未定义。

练习3:join(timeout)
主线程调用子线程的join(1000),状态变化?

Thread child = new Thread(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) {} }); child.start(); child.join(1000); // 主线程TIMED_WAITING System.out.println("主线程状态: " + Thread.currentThread().getState()); // RUNNABLE 

解释join(timeout)使调用线程进入TIMED_WAITING,但打印自身状态时为RUNNABLE。易错点:混淆超时和实际线程结束。

练习2:wait(timeout)
使用wait(500),状态如何?与sleep()对比。

Object lock = new Object(); Thread t = new Thread(() -> { synchronized (lock) { try { lock.wait(500); } catch (InterruptedException e) {} // TIMED_WAITING } }); t.start(); Thread.sleep(100); System.out.println("状态: " + t.getState()); // TIMED_WAITING 

解释:状态为TIMED_WAITING。易错点:wait(timeout)必须在同步块内调用,否则抛IllegalMonitorStateException

练习1:sleep()方法
线程调用sleep(1000),打印状态。时间结束后状态变化?

Thread t = new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) {} }); t.start(); Thread.sleep(100); System.out.println("状态: " + t.getState()); // TIMED_WAITING Thread.sleep(2000); System.out.println("状态: " + t.getState()); // TERMINATED 

解释:睡眠结束后状态变为TERMINATED(如果run()结束)。易错点:单位错误(sleep参数是毫秒)。

易错点与混淆点
  • 易错点:时间参数单位错误(如秒vs毫秒),导致等待时间不符预期。sleep()不会释放锁,而wait(timeout)会。
  • 混淆点:与WAITING混淆,因为两者都“等待”,但TIMED_WAITING有超时机制,自动唤醒。
  • 容易搞错的点Thread.join(timeout)如果超时,线程未结束,调用线程仍继续执行,但被join的线程可能还在运行。

6. TERMINATED(终止)

定义与原因

TERMINATED状态表示线程已执行完毕(run()方法正常结束)或因未捕获异常退出。线程进入此状态后,不能被重启(调用start()会抛异常),系统资源被释放。线程对象仍存在,但状态不可变。

代码案例
public class TerminatedStateExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { // run()方法执行完毕 }); thread.start(); thread.join(); // 等待结束 System.out.println("线程状态: " + thread.getState()); // TERMINATED } } 

线程结束后状态为TERMINATED。

练习

练习5:线程池影响
在线程池中,线程执行任务后状态如何?(模拟使用ExecutorService

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; ExecutorService pool = Executors.newSingleThreadExecutor(); pool.execute(() -> {}); // 线程池线程可能被重用,状态不一定是TERMINATED pool.shutdown(); 

解释:线程池线程任务结束后可能回到RUNNABLE(等待新任务),不直接TERMINATED。易错点:以为所有线程结束时都TERMINATED,忽略线程池机制。

练习4:isAlive()方法
使用isAlive()检查线程是否存活。终止后返回什么?

Thread t = new Thread(() -> {}); t.start(); t.join(); System.out.println("isAlive: " + t.isAlive()); // false System.out.println("状态: " + t.getState()); // TERMINATED 

解释isAlive()返回false,状态为TERMINATED。易错点:混淆isAlive()和状态API。

练习3:重启尝试
线程终止后,调用start()方法。会发生什么?

Thread t = new Thread(() -> {}); t.start(); t.join(); t.start(); // 第二次start 

解释:抛出IllegalThreadStateException。易错点:误以为线程可重用。

练习2:异常终止
线程抛出未捕获异常,状态如何?

Thread t = new Thread(() -> { throw new RuntimeException("错误"); }); t.start(); t.join(); System.out.println("状态: " + t.getState()); // TERMINATED 

解释:未捕获异常导致TERMINATED。易错点:忽略异常处理,线程静默终止。

练习1:正常结束
线程执行简单任务后结束。打印状态。

Thread t = new Thread(() -> {}); t.start(); t.join(); System.out.println("状态: " + t.getState()); // TERMINATED 

解释:状态为TERMINATED。易错点:未使用join()确保线程结束,导致状态打印过早。

易错点与混淆点
  • 易错点:线程终止后仍尝试操作(如start()),导致异常。开发者可能未处理线程异常,导致意外终止。
  • 混淆点:与RUNNABLE混淆,因为线程结束前可能短暂处于RUNNABLE。isAlive()方法更直接判断存活。
  • 容易搞错的点:在线程池中,线程对象被重用,状态不固定;直接创建线程时,TERMINATED是最终状态。

总结与常见混淆点对比

线程状态反映了并发编程的核心行为。以下是关键混淆点总结:

  • RUNNABLE vs BLOCKED:RUNNABLE是主动等待CPU,BLOCKED是被动等待锁。I/O阻塞在Java中可能不改变状态。
  • BLOCKED vs WAITING:BLOCKED只针对synchronized锁,自动恢复;WAITING需要显式唤醒,适用于wait()park()
  • WAITING vs TIMED_WAITING:WAITING无超时,TIMED_WAITING有超时自动唤醒。sleep()是TIMED_WAITING,但不会释放锁。
  • TERMINATED:线程结束后不可重启,isAlive()为false。

本篇的讲解就在这里啦~希望堆大家有所帮助!~

Read more

飞算JavaAI插件深度体验:三天任务半小时搞定,AI编程的革命性突破

飞算JavaAI插件深度体验:三天任务半小时搞定,AI编程的革命性突破

文章目录 * 飞算JavaAI插件深度体验:三天任务半小时搞定,AI编程的革命性突破 * 一、引言:从绝望到惊喜的转变 * 二、飞算JavaAI初体验:对话即开发 * 2.1 插件安装与配置 * 2.2 需求分析:AI理解业务场景 * 2.3 接口设计:从需求到API * 2.4 数据库设计:智能表结构生成 * 2.5 业务逻辑生成:核心功能实现 * 2.6 一键生成源码:项目快速构建 * 三、项目构建完成:效率提升的震撼体验 * 3.1 代码质量评估 * 四、实际运行测试:验证AI生成代码的可用性 * 4.1 接口测试结果 * 五、性能对比:传统开发 VS AI辅助开发

【JDK】-JDK 17 新特性整理(比较全)

【JDK】-JDK 17 新特性整理(比较全)

JDK 17 新特性 1、JDK 17中的Pattern类增强了哪些功能? 1. 新增asMatchPredicate方法: JDK 17的Pattern类新增了asMatchPredicate方法,可以将正则表达式编译为Predicate。 2. 增强了Unicode属性支持: JDK 17中的Pattern类增强了对Unicode属性的支持,使得正则表达式可以更好地处理Unicode字符。 3. 引入了新的转义语法: JDK 17引入了一种新的转义语法,可以更方便地转义正则表达式中的特殊字符,提高了正则表达式的可读性和可维护性。 4. 优化了性能: JDK 17对Pattern类的底层实现进行了优化,提升了正则表达式匹配的性能和效率。 5. 增加了对断言的支持: JDK 17中的Pattern类增加了对断言的支持,可以更灵活地进行正则表达式的匹配和处理。 2、JDK 17中的HTTP/2 Client有哪些新特性? 1. 提供了WebSocket支持: JDK 17中的HTTP/2 Client新增了对WebSocket的支持,使得开发者可以更方便地进行WebS

FastJson2 完整使用指导文档(Java 后端企业级实战版)

FastJson2 完整使用指导文档(Java 后端企业级实战版)

以下是一份专为 Java 后端开发者设计的 FastJson2 详细使用指导说明文档,涵盖定义、作用、必要性、核心功能、与主流工具对比、企业级实战建议,并附带带详细中文注释的代码示例,助你和团队高效落地。 📄 FastJson2 完整使用指导文档(Java 后端企业级实战版) 适用人群:Java 后端开发者、架构师、技术负责人 目标:全面掌握 FastJson2 的核心能力,替代旧版 FastJson / Jackson / GSON,提升序列化性能与安全性,推动团队标准化落地 一、FastJson2 是什么? FastJson2 是阿里巴巴开源的下一代高性能 JSON 库,是 FastJson 1.x 的彻底重构版本,于 2022 年正式发布。它在性能、安全性、标准兼容性、

Java LLM开发框架全面解析:从Spring AI到Agents-Flex

Java LLM开发框架全面解析:从Spring AI到Agents-Flex

🧑 博主简介:ZEEKLOG博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可关注公众号 “ 心海云图 ” 微信小程序搜索“历代文学”)总架构师,16年工作经验,精通Java编程,高并发设计,分布式系统架构设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。 🤝商务合作:请搜索或扫码关注微信公众号 “ 心海云图 ” Java LLM开发框架全面解析:从Spring AI到Agents-Flex 在人工智能席卷全球的今天,Java开发者无需转向Python生态,也能充分利用大语言模型的强大能力,这得益于日益成熟的Java LLM开发框架。 近年来,随着大语言模型(LLM)技术的迅猛发展,AI能力已成为现代应用开发不可或缺的部分。作为企业