- 博客(53)
- 收藏
- 关注
原创 volatile 的作用
摘要:本文探讨了volatile关键字在单例模式中的双重作用:保证内存可见性和禁止指令重排序。通过分析DCL(双重检查锁定)单例实现,指出若无volatile修饰,JVM可能对对象创建的三个步骤(分配内存、初始化、赋值)进行重排序,导致多线程环境下返回未完全初始化的对象。重点阐述了volatile如何通过禁止重排序和保证可见性来确保线程安全,并警告去除volatile可能引发难以复现但严重的并发问题(如Heisenbug)。该机制自Java5起成为实现线程安全单例模式的关键保障。
2025-12-20 21:33:29
199
原创 Volatile 解决内存可见性问题
这段代码存在一个典型的 Java 多线程可见性问题,会导致 线程t1无法看到t2对flag的修改,从而陷入死循环。
2025-12-20 20:14:35
260
原创 Java 多线程标志位的使用
必须保证内存可见性问题:一个线程修改标志位,另一个线程可能永远看不到更新。原因:CPU 缓存、JVM 优化导致变量值未同步到主内存。
2025-12-20 19:11:55
570
原创 字节流与字符流读写
即 8 位二进制数。:它不管你读的是什么文件(是图片、视频还是文本),它都把内容当成一串来搬运。读取的就是纯粹的字节。如果你用打印,看到的是内存中的真实二进制数据。:所有类型的文件(万能)。
2025-12-20 10:47:20
467
原创 HashTable、HashMap、ConcurrentHashMap 之间的区别
简单记忆要线程安全且高并发 →单线程 →HashMap避免使用HashTable(历史遗留,性能差)
2025-12-16 21:14:58
127
原创 ReentrantLock 与 synchronized 的区别
Java 中的和都是用于实现线程同步的机制,但它们在功能、使用方式和性能等方面存在显著差异。
2025-12-16 20:24:58
235
原创 锁策略、CAS 机制以及 synchronized 优化过程
如果持有锁的线程很快释放,自旋线程就能立即获取,避免了阻塞/唤醒的开销。如果一系列连续的操作都在对同一个对象加锁(如循环内加锁),JVM 会将锁的范围扩大(粗化),变成一次加锁解锁,减少频繁申请释放锁的开销。“谁抢到是谁的”:允许插队,吞吐量高,但可能导致线程饥饿。如果自旋次数超过阈值(或等待线程过多),JVM 会将轻量级锁膨胀为重量级锁,此时未获取到锁的线程会被挂起。它偏向于第一个访问的线程,如果没有竞争,该线程以后每次进入同步块都不需要做任何同步操作。“先来后到”:线程获取锁的顺序严格按照申请的顺序。
2025-12-09 21:46:40
670
原创 synchronized
每次退出同步块时,计数器递减。当一个线程获取到锁后,其他试图获取同一把锁的线程会被阻塞,直到持有锁的线程释放锁。新来的线程和队列中等待的线程有同等的概率竞争到锁,这可能导致某些线程长时间无法获取锁(饥饿),但整体吞吐量通常比公平锁更高。在轻量级锁状态下,如果线程获取锁失败,它不会立即挂起(阻塞),而是会执行一段忙循环(自旋),看持有锁的线程是否很快就会释放。如果锁对象只有一个线程访问,JVM 会将锁“偏向”该线程,线程再次进入时不需要进行任何同步操作(CAS),直接通过检查对象头中的线程 ID 即可。
2025-12-09 21:06:51
950
原创 Java线程池
Java线程池是一种,它通过复用已创建的线程来执行多个任务,而不是为每个任务都新建一个线程。Java线程池的工作原理是其高效管理并发任务的核心,其本质是一个基于和的复杂调度系统。其工作流程可以概括为:任务提交后,线程池根据当前状态(核心线程数、队列容量、最大线程数)决定是创建新线程执行、放入队列缓冲,还是直接拒绝。
2025-12-09 20:30:14
1244
原创 Java 线程的几种状态
主要进入条件:调用 Thread.sleep(long)、 Object.wait(long)、Thread.join(long) 或 LockSupport.parkNanos() 等带超时参数的方法。主要进入条件:调用 Object.wait()(无参)、Thread.join()(无参) 或 LockSupport.park()主要退出条件:被其他线程通过 notify() / notifyAll() 唤醒 或 被中断 -> RUNNABLE。主要进入条件:start() 方法被调用;
2025-11-17 16:16:18
305
原创 Java 不同创建线程的方式什么时候才可以使用 this 来获取线程的引用
3. lambda 表达式也不可以,因为 lambda 表达式中的 this 指向外部类实例是有 lambda 的设计哲学和实现机制来决定的。因为匿名类继承了 Thread 类,所有它具有 Thread 的所有方法,包括 getName().所以需要 Thread.currentThread()来获取当前正在执行代码的线程对象。2.实现 Runnale ,不能用 this 来获取线程信息。1.匿名内部类可以使用 this 来获取当前线程的引用。this 的指向规则。运行时有两个独立对象。
2025-11-11 22:09:41
164
原创 匿名内部类与外部类有什么区别
匿名内部类是一种特殊的内部类,它与常规的外部类(包括顶级类和命名内部类)有显著区别。匿名内部类:定义和实例化同时完成,没有独立的类声明。可以访问外部类的所有成员(包括 private)代码紧凑:简单实现可以写在调用点附近,提高可读性。外部类/命名内部类:先定义类结构,再实例化。快速原型:临时性的、一次性的实现非常方便。可维护性:复杂逻辑有独立的类文件结构清晰。可复用性:可以在多个地方实例化和使用。继承体系:可以建立完整的类层次结构。何时使用命名类(外部类/内部类)1.匿名内部类的定义方式与语法。
2025-11-11 20:55:09
318
原创 进程与线程的区别
线程共享其所属进程的地址空间和资源(如全局变量、打开的文件)。创建或销毁一个线程,由于它们共享进程的绝大部分资源,只需分配少许独立的栈空间和寄存器即可,开销很小,速度非常快。进程像一个独立的公司,它拥有自己独立的“财产”,如内存空间(代码段、数据段、堆、栈)、文件描述符、I/O设备等。公司里的“办公空间”(进程的资源),但每个员工有自己的“工作任务流”(独立的程序计数器、栈空间和寄存器状态)。创建或销毁一个进程,需要为其分配或回收独立的内存空间、文件资源等,这涉及大量的系统调用和操作,开销较大,速度较慢。
2025-11-06 16:11:44
207
原创 事务的隔离级别及其存在的相应的问题
事务的隔离级别有:1、READ UNCOMMITTED --> 读未提交由于在读取数据时不做任何限制所以并发性能很高,但是会出现⼤量的数据安全问题,比如在事务A中执行了⼀条 INSERT 语句,在没有执行 COMMIT 的情况下,会在事务B中被读取到,此时如果事务A执行回滚操作,那么事务B中读取到事务 A写入的数据将没有意义,我们把这个理象叫做 "脏读"。2、READ COMMITED --> 读已提交与不可提交。
2025-10-26 09:23:04
325
原创 索引什么时候会失效
8.针对复合查询,其中 a,b,c 为复合索引,查询时,可以按照 a、a,b、a,b,c、a,c、b,c 其他的不行,得有一定顺序。4.查询条件中包含了 or , or 一边是索引列的条件,另一边是非索引列的条件,还是会一条一条的遍历。2.查询的时候,使用了索引列作为条件,但是索引列的值比较单一,此时索引无法发挥效果。给一个表创建索引时,不是所有的查询都能通过索引来完成,以下来分析索引失效的情况。3.查询的时候,查询条件针对索引列进行了表达式运算或对索引列进行了隐式类型转换。如果是 and 则没事。
2025-10-19 15:48:25
131
原创 MySQL 之索引为什么选择B+树
1.哈希表:哈希表搜索的时间复杂度是 O(1),查询速度也快,但是哈希表通过哈希函数将键映射到存储位置,但该过程不保证数据的物理存储顺序与键的逻辑顺序一致。3.红黑树:虽然是平衡或近似平衡的,但是毕竟是二叉结构,在检索数据时,由于表中的数据都是存在磁盘中的,所以每次范围某个节点的子节点时都会发生一次磁盘IO(磁盘I/O(Input/Output)指计算机系统中磁盘的输入输出操作,包括从磁盘读取数据(输出)和向磁盘写入数据(输入),是数据存储与传输的核心过程,直接影响系统性能)。但是不是最佳的结构。
2025-10-19 14:48:04
345
原创 树与二叉树
数据的线性存储结构有哪种,结构有几种什么是树什么不是树什么是结点的度什么是树的度什么是叶子结点或终端结点什么是双亲结点或父结点什么是孩子结点或子结点什么是根结点什么是结点的层度什么是树的高度或深度什么是非终端结点或分支结点什么是兄弟结点什么是堂兄弟结点什么是结点的祖先什么是子孙什么是森林。
2025-08-12 22:06:16
916
原创 Java 队列
Queue 中的 add 与 offer 的区别。offer、poll、peek 的模拟实现。Queue 和 Deque 有什么区别。数据入队列时一定是从尾部插入吗。数据出队列时一定是从头部删除吗。数据入队列时一定是从尾部插入吗。数据出队列时一定是从头部删除吗。熟悉 Deque 接口的方法。队列一般用什么哪种结构实现。队列是用哪种结构实现的。Queue 接口的方法。如何利用顺序表实现队列。队列的基本运算有什么。如何利用链表实现队列。队列的基本运算有什么。
2025-07-29 21:00:25
221
原创 数据结构之顺序表&链表&栈
什么是 listlist 的使用线性表是什么顺序表是什么顺序表和线性表的关系顺序表和数组的区别List 和 ArrayList 的关系如何自己模拟实现 myArrayListArrayList 的构造ArrayList 的常见方法以下两种写法有什么区别AraryList 的遍历的代码实现(6种)iterator 方法的使用方法及原理为什么 AraryList 、List 、Collection 、 Iterable 接口中都有 iterator 方法。
2025-07-28 20:10:01
814
原创 复杂度+包装类型+泛型
本文摘要介绍了Java集合框架、数据结构、算法及复杂度分析等核心概念。重点讲解了包装类的装箱/拆箱机制(自动装箱范围为-128~127)、泛型的实现原理(类型擦除和桥接方法)及使用(上界通配符)。详细说明了List接口与ArrayList实现类的关系,包括顺序表实现原理及构造方法。通过代码示例展示了泛型类的设计(如求数组最大值)和使用注意事项(包装类不能直接比较)。最后比较了ArrayList<Integer>与List<Integer>两种声明方式的接口编程差异。
2025-07-20 19:46:26
971
原创 Java 之异常
自定义异常的使用场景自定义异常需要继承 Exception 或者 RuntimeException继承 Exception 、RuntimeException分别表示什么如何实现自定义异常(如何定义运行时异常与编译时异常)如果定义的是运行时异常,需要声明吗可以实现构造方法,并同时传参进行信息交互throw 后面可以加 return 吗。
2025-07-14 10:20:46
414
原创 Java 之字符串 --- String 类
String 类型属于哪种类String 是被 publid final 修饰的类String 提供的构造方法什么叫做字符串常量池“池”的理解str1 用 ''=='' 与str2 比较时,比的是地址字符串的内存存储。
2025-07-12 21:32:47
699
原创 Java 之数组自查
数组作为函数参数传递,参数传数组传的是引用,相当于说是地址,所谓的“引用”本质上只是存了一个地址,Java 将数组设定成引用类型,这样的话后续进行数组参数传递,其实只是将数组的地址传入到函数形参中,这样可以避免对整个数组的拷贝(数组可能比较长,拷贝开销大)给定一个整数数组 nums 和一个整数目标值 target ,请你在该数组中找出和为目标之 target 的那两个整数(与返回数组相关)给你一个整数数组 arr,请你判断数组中是否存在连续三个数都是奇数,存在返回 true,不存在返回 false。
2025-07-08 15:30:04
704
原创 Java 之抽象类接口自查
如果一个抽象类A·继承了抽象类B, 那么在抽象类A中可以不重写抽象类B 中的方法,但是当一个普通类C 继承了这个抽象类A,此时在普通类 C 中不仅要重写抽象类 B 中的方法还要重写抽象类Az的方法。抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰。接口当中的方法不能有具体的实现,但是这个方法被 static 或者 default 修饰之后可以有具体的实现。当一个普通类继承了抽象类之后,这个普通类需要重写父类抽象类的抽象方法。
2025-07-04 15:17:20
300
原创 Java 之多态自查
当返回值类型构成协变类型(返回值类型构成父子类关系),也是可以构成重写的(其实也可以认为返回值一样)要求子类的访问修饰限定符类型限定范围不小于父类的访问修饰限定符限定类型。重写与重载的区别(参数列表、返回类型、访问修饰限定符)运行时绑定/动态绑定发生的前提条件(有3个)被 private 修饰的方法不能被重写。被 final 修饰的方法也不能被重写。重写/覆盖/复写是什么,有什么特征。运行时绑定/动态绑定时什么意思。静态绑定/编译时绑定是什么意思。重写的访问修饰限定符的限制。重写的快捷键(有两种方法)
2025-07-03 13:06:36
321
1
原创 Java之继承自查
父类的静态代码块、子类的静态代码块、父类的实例代码块、子类实例代码块、父类的构造代码块、子类的构造代码块的执行顺序。为什么如果子类继承了父类,子类完成构造的时候(执行完子类的构造方法),要先帮助父类进行构造。不重名时,当子类继承父类以后,如何通过子类对象是可以访问父类当中的成员变量和成员方法的。如果子类继承了父类,子类完成构造的时候(执行完子类的构造方法),要先帮助父类进行构造。优先访问子类自己的,如果子类没有,就去找父类,父类有就是父类的,没有就报错了。子类的构造方法与父类的构造方法执行的顺序。
2025-07-01 10:49:44
314
原创 类和对象自查
构造代码块(实例代码块)就是构造代码块是定义在类中但不在任何方法内的代码块,使用 {} 包围。想在一个包中的类里实例化另一个包中的类,通常需要使用import语句导入目标类。同一个包下,怎么在一个类下访问并修改另外一个类中的由private修饰的局部变量。同一包中的同类、同一包中的不同类、不同包中的子类、不同包的非子类都是什么意思。每个对象都存在一个相同的共同点,如全班同学都是一个班上的。静态代码块、实例代码块、构造方法的执行顺序。静态成员变量的作用(存在的意义)类的初始化(不同的初始方法)
2025-06-29 21:05:49
321
原创 Java 中数组的重难点
其中 array1 = array2 意味着 array1 这个引用指向了 array2 这个引用所指向的对象。所以 array1[2] = 300;会改变原来 array2 引用指向的数组的第3个元素的值。
2025-05-22 16:38:18
181
原创 汉诺塔的实现
可以发现所有层数的汉诺塔都得先把 n - 1 层盘按从下到上,从大到小的顺序放置到 B 上,通过C把A上的 n - 1 个盘放到 B hanoi(n - 1, pos 1, pose 3, pose 2),然后把 A 上的最大的放到 C 上 move(pos1, pose2)。后续 n - 1次同理 把 B 上的 n - 1 个盘通过 A 放到 C 上 hanoi(n - 1,pos2, pos1, pos 3)可以观察到第3层中有一个状态与第2层类似。欢迎大家在评论区交流。写成Java代码即为。
2025-05-22 14:49:35
224
原创 关于java数据类型与变量、运算符、程序逻辑控制、输入输出、方法有感(与C不一样的部分)
Java 的整形家族比 C 多了 byte 类型Java 的整形数据类型的二进制均为有符号整形,最左边的均为符号位,所以数据表达范围是 [-pow(2,n),pow(2,n - 1)]Java 的 boolean 类型与整形类型并没有关联(如 非0 不再代表 true 、0 不再代表 false)Java 由类型的加大版本,可以理解为有更多的功能 ,如 Integer、Character、Long、Short、Byte、Float、Double、Boolean。
2025-05-17 19:10:15
348
原创 青蛙跳台阶的三种解决方法
如何理解:可把 tem 看作 f(n) , first 看作f(n - 1), second 看做 f(n-2);first ,second 不断更新,不断储存着 f(n - 1) 与 f(n -2) 的值,这时 n 也在变化。好处:这种方法的核心在于只保存当前状态及其前几个必要状态的信息,从而减少不必要的存储开销并提高运行效率。思路:本质与递归并无区别,只不过通过循环的方式,只把上一次的的结果存下来了。法三:斐波那契数列法。
2025-04-25 21:16:50
206
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅