StringBuffer 与 StringBuilder 的三大区别
虽然两者都用于可变字符串操作,但在线程安全、内部缓存和性能上存在差异。 线程安全性StringBuffer 所有公开方法都使用 synchronized 修饰,线程安全。 StringBuilder 未同步,线程不安全。 java// StringBuffer 中的方法public synchronized StringBuffer append(String str) {// …} 内部缓存机制StringBuffer 内部维护了一个 toStringCache 数组,在 toString() 时复用,避免重复拷贝。 java// StringBufferpublic synchronized String toString() {if (toStringCache == null) {toStringCache = Arrays.copyOfRange(value, 0, count);}return new String(toStringCache, true);} /...
UUID:通用唯一标识符
UUID(Universally Unique Identifier)是一个 128 位的全局唯一标识符,常用于分布式系统中生成唯一 ID。 格式与示例标准 UUID 形如:550e8400-e29b-41d4-a716-446655440000共 32 位十六进制数,分为 5 组:8-4-4-4-12。 生成方式javaimport java.util.UUID; public class UUIDDemo {public static void main(String[] args) {UUID uuid = UUID.randomUUID();System.out.println(uuid.toString());}}特点与用途唯一性:理论重复概率极低。 无需中心协调:各节点可独立生成。 应用场景:数据库主键、文件命名、会话标识、分布式追踪等。 注意字符串形式较长(36 字符),存储和传输有一定开销。 无序性,不适合直接作数据库索引(可考虑有序 UUID 变种)。
Java 基本数据类型转换规则
Java 中的 8 种基本数据类型在一定条件下可相互转换,分为自动转换和强制转换。 自动类型转换范围小的类型可自动转换为范围大的类型,例如: javaint a = 100;long b = a; // 自动转换 double d = 3.14;float f = (float) d; // 需强制转换注意数值溢出: javaint x = 1_000_000_000;int y = 2_000_000_000;long sum = (long) x + y; // 先转型再计算,避免溢出强制类型转换将范围大的类型转换为范围小的类型时,需显式强制转换,可能丢失精度或溢出。 javadouble pi = 3.14159;int intPi = (int) pi; // 结果为 3 int big = 300;byte small = (byte) big; // 溢出,结果...
Java 序列化的五个关键细节
序列化不仅是将对象转为字节流,更涉及版本兼容、安全控制、性能优化等多个方面。 支持类演变通过 serialVersionUID 控制版本兼容性。新增字段、将 static 改为非 static 等修改,反序列化时可自动处理(新增字段为默认值)。 javapublic class Person implements Serializable {private static final long serialVersionUID = 1L;private String name;// 后续版本可增加 private int age;} 可自定义序列化逻辑通过实现 writeObject 和 readObject 方法,可在序列化前后对数据进行加密或校验。 javaprivate void writeObject(ObjectOutputStream out) throws IOException {// 加密敏感数据out.defaultWriteObject();} private void readObject(Objec...
深入理解 Java 包装类
包装类(Wrapper Classes)将基本类型封装为对象,使基本类型能参与面向对象操作。 对应关系基本类型 包装类byte Byteshort Shortint Integerlong Longfloat Floatdouble Doublechar Characterboolean Boolean主要用途集合泛型集合不能存储基本类型,必须使用包装类。 允许空值成员变量或方法参数可能需要表示“无值”状态。 javaprivate Integer score; // 可为 null,表示“未评分”数值边界处理避免基本类型的默认值(如 0)被误认为有效值。 自动装箱与拆箱Java 5 引入自动转换机制: javaInteger a = 100; // 自动装箱:Integer.valueOf(100)int b = a; // 自动拆箱:a.intValue() // 实际等价于:Integer a = Integer.valueOf(100);int b = ...
三种常见的类级别错误
Java 开发中,与类加载和类型转换相关的错误尤为常见,主要包括以下三种: ClassNotFoundException当显式加载类时(如 Class.forName() 或 ClassLoader.loadClass()),在类路径中找不到指定类时抛出。 javatry {Class<?> clazz = Class.forName(“com.example.NonExistClass”);} catch (ClassNotFoundException e) {e.printStackTrace();} NoClassDefFoundErrorJVM 隐式加载类时抛出,通常是因为编译时存在某个类,但运行时缺失对应的 .class 文件或依赖包。 java// 编译通过,但运行时缺少相关 jar 包public class MyApp {public static void main(String[] args) {ExternalDependency obj = new ExternalDependency(); ...
Java 可变参数的那些“坑”
可变参数(Varargs)允许方法接受数量不定的参数,语法为 Type… args。虽然灵活,但使用不当容易引发问题。 示例分析javapublic static void main(String[] args) {printFormatted(“姓名=%s,备注=%s”, “张三”, “优秀”);// 输出:姓名=张三,备注=优秀} private static void printFormatted(String format, Object… args) {String result = String.format(format, args);System.out.println(result);}上述代码运行正常。但若调整参数传递方式: javaprivate static void printFormatted(String format, Object… args) {// 错误:将 args 数组作为单个参数传递String result = String.forma...
JVM的锁优化策略:从偏向锁到锁消除
在高并发环境下,锁的使用是保证线程安全的重要手段,但频繁的加锁解锁也会带来显著的性能开销。为了减少同步操作带来的损耗,Java虚拟机(JVM)实现了一系列精妙的锁优化技术,旨在不牺牲线程安全的前提下提升程序执行效率。 偏向锁 (Biased Locking)目标:消除无竞争情况下的同步开销。原理:当锁对象第一次被线程获取后,JVM会将其标记为“偏向模式”,并将线程ID记录在对象头中。之后该线程再次请求该锁时,无需进行任何实际的同步操作(如CAS),可以直接进入临界区。适用场景:适用于锁被单个线程长时间独占的场景。在竞争激烈的环境下,偏向锁的撤销成本可能高于其收益。 轻量级锁 (Lightweight Locking)目标:在低竞争情况下,避免线程在操作系统层面被挂起(用户态到内核态的切换)。原理:当偏向锁失败(即存在另一个线程尝试获取锁)时,JVM不会立即升级为重量级锁。它会将对象头中的标记替换为一个指向当前线程栈中锁记录的指针(即“锁记录”空间)。获取锁的过程通过CAS操作完成。若成功,线程继续执行;若失败,说明存在竞争,锁将“膨胀”为重量级锁。适用场景:线程交替执行,持有...
Java多线程协同的核心机制:等待与唤醒
在Java多线程编程中,线程间的协调与通信是构建稳定并发程序的关键。除了共享内存与锁机制外,Java还提供了一组基于对象监视器(Monitor)的通信原语:wait(),notify(), 以及 notifyAll()。这三个方法共同构成了线程间“等待-通知”模式的基础。 方法定义与归属wait():使当前线程暂停执行并进入等待状态,同时释放其持有的对象锁。线程将停留在对象的等待集中,直到被其他线程唤醒。 notify():从在该对象上等待的线程中,任意选择一个并将其移出等待集,使其重新进入锁竞争状态。 notifyAll():唤醒在该对象上等待的所有线程,使它们全部移出等待集并重新竞争锁。 这三个方法并非定义在 Thread 类中,而是位于 Object类。这是因为锁是关联于对象实例的(每个对象都有一个内置监视器锁),线程通过获取对象的锁来进入同步区域。因此,让线程等待或唤醒的操作自然应该由锁的持有者——对象来提供。 http://qianniu.javastack.cn/18-6-1/82637503.jpg wait(long timeout) 方法允许设置一个最大等待时长...
Fork/Join框架:分而治之的并行计算利器
面对大规模计算任务,单线程顺序处理往往力不从心。Java 7引入的Fork/Join框架,正是为了简化此类问题的并行化处理而生。它将“分而治之”(Divideand Conquer)的算法思想与线程池相结合,自动将大任务递归分解为小任务并行执行,最后合并结果,特别适合处理可递归分解的计算密集型任务。 核心概念与原理 核心思想Fork(分叉):将一个大任务递归地分割(fork)成若干个互不依赖的子任务。 Join(合并):等待所有子任务执行完毕后,将它们的结果合并(join)起来,得到最终结果。 工作窃取算法这是Fork/Join框架高效的关键。每个工作线程维护一个双端队列来存放分配给它的任务。 线程正常从自己队列的队头取出任务执行。 当某个线程自己的队列为空时,它会随机从其他线程队列的队尾“窃取”一个任务来执行。优势:减少了线程因等待任务而产生的空闲时间,充分利用了CPU资源,实现了负载均衡。 https://res.infoq.com/articles/fork-join-introduction/zh/resources/image3.png 核心...
