- 博客(459)
- 收藏
- 关注
原创 多线程篇·线程相关知识
当多个线程同时扩容,由于 HashMap 非线程安全,若两个线程同时反转,可能形成链表循环(如 A 节点指向 B 节点,B 节点又指回 A 节点),这样下次获取 key 对应的 value 时,遍历链表会无法结束,从而导致 CPU 100%。若不采取任何措施,value 永远无法被 GC 回收,若线程长时间不销毁,可能产生内存泄漏。若被请求的共享资源被占用,则需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH(虚拟的双向队列)队列锁实现的,即将暂时获取不到锁的线程加入到队列中。
2024-11-15 14:40:50
583
原创 在 Java 中,什么时候用重载,什么时候用重写
重载: 提供多种方法签名。目的是提高程序的多样性和健壮性,以适配不同场景使用时,使用重载进行扩展;重写: 增强剂,在不修改原方法的基础上增强或改变行为。重载必须修改方法的形参列表,返回值类型不能修改,访问权限也不能更严格。重写只能用于子类对父类方法的扩展或修改,不能抛出比父类方法声明的异常更多的异常。
2024-11-13 10:16:41
323
原创 ThreadLocal有哪些应用场景?它底层是如何实现的
3.用户会话或请求上下文:在Web应用中,可以使用ThreadLocal存储当前请求或会话的相关信息(如用户ID、权限信息等),使得在请求的生命周期内,任何地方都能方便地获取这些信息,而不会混淆不同用户的上下文。综上所述,ThreadLocal通过在每个线程中维护一个独立的存储空间,实现了线程间数据的隔离,是解决某些特定场景下线程安全问题的有效工具。5.线程安全的单例模式:在需要线程安全的单例对象时,可以通过ThreadLocal为每个线程提供单独的实例,避免多线程并发访问的同步问题。
2024-11-12 14:56:55
291
原创 创建线程池有哪几种方式
:固定大小的线程池,适用于任务量已知且相对固定的场景,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;:单线程的线程池,适用于需要按顺序执行任务的场景,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
2024-11-12 11:55:41
543
原创 JDK、JRE、JVM之间的区别
JDK指的运行时候的需要的一些工具类和运行时环境,比如包括javac.exe ,javadoxc.exe 一系列用于编译字节码工具 打包文档的工具。JVM指的是Java的虚拟机,Java程序需要运行在虚拟机上,不同的平台都有自己的虚拟机,所以Java语言实现了跨平台。JRE指的是Java的运行时环境,包括需要的大量的类库和Java的虚拟机。
2024-11-12 11:13:22
190
原创 谈谈ConcurrentHashMap的扩容机制
在Java8中,摒弃了分段锁的设计,转而采用更细粒度的锁,即每个桶(bin)上的链表头节点作为锁的粒度,并引入了红黑树来优化链表过长时的查找效率。其扩容过程主要包括以下几个步骤:1.初始化新容量:当需要扩容时,会计算出新的容量,并创建一个新的、容量更大的table。扩容的触发条件通常是当元素数量超过当前容量与负载因子乘积时。2.迁移节点:扩容的核心在于将旧table中的元素重新分配到新的table中。这个过程不是一次性完成的,而是随着每次对map的操作逐步进行。
2024-11-12 11:07:25
536
原创 重载和重写的区别
5.重载:在同一个类中,当方法名相同,形参列表不同的时候 多个方法构成了重载,与修饰符无关,与返回值无关;1.定义:重载是在同一个类中定义多个具有相同名称但不同参数的方法;6.方法重写:父子类、接口和实现类之间的关系,子类可以重写父类方法,但是参数个数、类型、返回值必须相同。重写:参数列表必须要与被重写的相同;修饰符和抛出的异常不能在被重写的方法之外。重写是父类与子类的关系,是垂直关系;重载是同一个类方法中的关系,是水平关系。重载:必须有不同的参数列表;重写方法是子类对父类的方法进行重写。
2024-11-11 16:30:36
408
原创 多线程锁的升级原理是什么
轻量级锁:轻量级锁是指当锁是偏向锁的时候,被第二个线程 B 所访问,此时偏向锁就会升级为轻量级锁,线程 B 会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能。当一个线程已持有锁,另一个线程在自旋,而此时又有第三个线程来访时,轻量级锁也会升级为重量级锁。偏向锁的撤销:当有其他线程尝试竞争偏向锁时,偏向锁会被撤销,升级为轻量级锁。重量级锁:指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。锁的降级:JVM 并不支持锁的降级,即一旦锁升级为重量级锁,就不会再降级为轻量级锁或偏向锁。
2024-11-11 16:07:09
151
原创 创建线程有哪几种方式
继承 Thread 类:简单直观,适合初学者。实现 接口:灵活,解决单继承问题。实现 接口和:适合需要返回结果的任务。使用 框架:适合大规模并发任务的管理,提供高级功能。推荐使用 Executor 框架,因为它提供了更强大的功能和更好的性能。
2024-11-11 15:38:20
286
原创 线程池都有哪些状态
4.TIDYING(整理状态):当所有的任务(包括正在执行的和队列中的)都已完成,并且所有的worker线程(除了finalizer线程)都已经结束,线程池就会从SHUTDOWN或STOP状态转换到TIDYING状态。workCount 为 0。2.SHUTDOWN(关闭状态)当调用了线程池的`shutdown()`方法后,线程池进入此状态。1.RUNNING(运行状态):在这个状态下,线程池可以接收新的任务提交,并且能够处理已添加到任务队列中的任务。这是线程池的初始状态,也是最活跃的状态。
2024-11-11 15:24:50
178
原创 hashCode()与equals()之间的关系
在Java中,`hashCode()`和`equals()`方法之间存在紧密的关系,主要体现在它们共同作用于对象的比较和存储上,尤其是在集合(如HashSet、HashMap)和哈希表的实现中。4.HashCode和Equals都是在Object类中定义的,是对两个对象地址的比较,如果重写了Equals方法就必须重写HashCode方法。Equals返回的是true和false。1.hashCode()和equals()是Object类中定义的两个重要方法,用于对象的比较和哈希处理。
2024-11-11 15:15:28
216
原创 泛型中extends和super的区别
泛型中的 和 关键字用于设置类型参数的上下界,控制可以传递给泛型类型的参数类型。它们的区别在于限制的方向和用途:1.extends:2.super:总结来说, 通常用于确保可以安全地使用对象的特性(即读取),而 用于确保可以安全地插入对象(即写入)。在实际应用中,根据你需要执行的操作(读或写)来决定使用哪一个。
2024-11-11 15:05:29
296
原创 String、StringBuffer、StringBuilder的区别
在Java中,、、和都是用于处理字符串的类,但它们之间存在一些关键差异,主要涉及可变性、线程安全性和性能:1.String: -不可变性:对象一旦被创建,其内容就不能改变。任何对的操作,比如拼接、替换等,都会返回一个新的对象,而原对象保持不变。 -性能:由于每次修改都会创建新对象,因此在进行大量字符串操作时可能引起性能问题,尤其是在循环中连续拼接字符串 -线程安全: 因为字符串内容不可变,所以在多线程环境中不需要同步,天然线程安全。使用场景:
2024-11-11 11:59:18
157
原创 理解乐观锁和悲观锁
乐观锁:认为每次去拿数据的时候别人不会修改,所以不会上锁,但是每次要拿数据的时候都会先判断数据是否被别人修改悲观锁:认为每次去拿数据的时候别人都会修改,所以每次都会上锁。使用场景:乐观锁使用于多读少写的应用类型,这样可以提高吞吐量;相反的情况则使用悲观锁乐观锁和悲观锁是并发控制中两种常见的锁机制,它们分别基于不同的假设来处理数据的并发访问。
2024-11-09 13:12:03
180
原创 双亲委派模型
如果一个类收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器执行,如果父加载器还存在其父加载器,则进一步向上委托,依次递归,请求将最终到达顶层的启动类加载器,如果父类加载器可以完成父加载任务,就成功返回,如果父加载器无法完成加载任务,子加载器才会尝试自己去加载,这就是双亲委派模型。important;负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。
2024-11-09 10:53:21
703
原创 举例说明什么情况下会更倾向于使用抽象类而不是接口
接口和抽象类都遵循”面向接口而不是实现编码”设计原则,它可以增加代码的灵活性,可以适应不断变化的需求。
2024-11-05 18:31:36
256
原创 判断一个数是不是质数(素数)
i < n;质数(也称为素数)是指在大于1的自然数中,除了1和它本身以外不再有其他因数的数。换句话说,质数只能被1和它自身整除。
2024-11-05 18:01:27
375
原创 什么是java序列化?什么情况下需要序列化?
Java 序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。序列化是一种用于处理对象流的机制,它将对象的内容转换成一种可以在网络之间传输的形式。反序列化则是将这种形式的对象恢复成原来的对象。序列化和反序列化是Java中非常重要的技术,它们使得对象可以在不同的环境中进行传输和存储。通过实现接口,开发者可以方便地对对象进行序列化和反序列化操作,从而实现数据的跨平台共享和持久化存储。
2024-11-05 17:44:39
327
原创 try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗
finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。下面提供了一段示例代码和运行结果。问题的核心在于当catch块中有return语句时,finally块是否还会被执行。
2024-11-05 17:25:38
283
原创 Synchronized用过吗,其原理是什么
synchronized是可重入锁,每部锁对象会有一个计数器记录线程获取几次锁,在执行完同步代码块时,计数器的数量会-1,直到计数器的数量为0,就释放这个锁。重量级锁:轻量级锁尝试去获取到锁,如果获取失败线程就会进入阻塞状态,该锁会升级为重量级锁,重量级锁时,来竞争锁的所有线程都会阻塞,性能降低。轻量级锁:当锁是偏向锁时,有另外一个线程来访问,会撤销掉偏向锁,然后升级为轻量级锁,这个线程会通过自旋方式不断获取锁,不会阻塞,提高性能。轻量级锁:轻量级锁所适应的场景是线程交替执行同步块的场合。
2024-11-05 17:14:37
253
原创 java中的Math.round(-1.5)等于多少
1、ceil:向上取整 向上取整:无论小数点后面的数字是多少,都向上取整到最接近的整数。向下取整:无论小数点后面的数字是多少,都向下取整到最接近的整数。Math提供了三个与取整有关的方法:ceil、floor、round (1)ceil:向上取整;-1 等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
2024-11-04 18:33:30
203
原创 Iterator和ListIterator有什么区别
Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。ListIterator 从 Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。总的来说,ListIterator 相比 Iterator 更强大,因为它不仅支持正向遍历,还支持逆向遍历,并且提供了更多的操作方法。然而,ListIterator 只能在 List 集合及其子类中使用,而 Iterator 可以用于任何可迭代的集合。
2024-11-04 18:18:56
353
原创 抽象类和接口的区别
这两种设计模式各有优势,选择使用哪种取决于具体的业务需求和设计目标。抽象类 (Abstract Class)接口 (Interface)
2024-11-04 17:50:10
394
原创 实例化对象有哪几种方式
这些方法都可以用来创建或复制对象,但适用的场景不同。例如,`new` 关键字是最常用的方法,而 `clone()` 方法则适用于克隆对象。反射机制可以动态地创建对象,适合在运行时加载类。序列化和反序列化则常用于网络传输或持久化存储。序列化是将一个对象转换为字节流的过程,而反序列化则是将字节流还原为对象的过程。//将一个对象实例化后,进行序列化,再反序列化,也可以获得一个对象。2. **clone() 方法**3. **通过反射机制创建**1. **new 关键字**4. **序列化反序列化**
2024-11-04 17:33:54
411
原创 操作字符串都有哪些类以及它们之间有什么区别
StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。- 操作频繁的情况下,如果在单线程环境中,推荐使用 StringBuilder;- 线程安全,但由于加锁的原因,效率不如 StringBuilder。- 线程不安全,效率高,多用于单线程环境。- 不频繁的字符串操作建议使用 String。- 也适用于需要频繁修改字符串的操作。- 适用于需要频繁修改字符串的操作。- 适用于不频繁修改字符串的情况。
2024-11-04 17:24:38
377
原创 介绍一下四种引用类型
在内存足够的时候,软引用不会被回收,只有在内存不足时,系统才会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会跑出内存溢出异常。- 程序可以通过判断引用队列中是否加入了引用,来判断被引用的对象是否将要被垃圾回收,这样可以在对象被回收之前采取一些必要的措施。程序可以通过判断引用队列中是否加入了引用,来判断被引用的对象是否将要被垃圾回收,这样可以在对象被回收之前采取一些必要的措施。- 当垃圾回收器准备回收一个对象时,如果发现它还有引用,就会在回收对象之前,把这个引用加入到引用队列中。
2024-11-04 10:28:26
307
原创 路过的朋友,欢迎来看看通俗易懂版本的Nacos
一个更易于构建云原生应用的动态服务发现、服务配置和服务管理平台。开发测试环境和生产环境的资源(如配置、服务)隔离等,比如dev和prod。在没有明确指定配置的情况下, 默认使用的是 DEFAULT_GROUP。
2024-06-04 16:44:36
307
原创 java什么时候声明static方法
当你有一个方法不需访问对象状态,即不需要访问类的非静态成员变量,那么这个方法可以声明为static。总的来说,当你希望一个方法能够不依赖于类的任何实例,或者该方法的操作与类的实例状态无关,且期望在不实例化对象的情况下就能使用该方法时,就应该声明为static。:在实现单例模式时,提供一个静态的getInstance方法来返回唯一的实例对象,这也是static方法的一个典型应用。必须声明为static,因为它是在类加载时由JVM调用的,并且不需要创建类的实例。,就需要初始化时,声明为static。
2024-06-04 16:12:56
321
原创 java所有集合的相互关系是什么
Java集合框架是一个设计精良、功能强大的工具集,用于存储和操作对象集合。它大致分为以下几类,并且各类之间存在一定的层级关系和功能差异:### 顶级接口(根接口)1. **Collection**: 是最基础的集合接口,所有集合类都直接或间接实现了这个接口。它定义了基本的集合操作,如添加元素(`add(E element)`)、删除元素(`remove(Object o)`)、清空集合(`clear()`)、检查集合是否为空(`isEmpty()`)等。
2024-05-14 15:14:42
385
原创 String、StringBuffer、StringBuilder的区别
在Java中,`String`、`StringBuffer`、和`StringBuilder`都是用于处理字符串的类,但它们之间存在一些关键差异,主要涉及可变性、线程安全性和性能:1.String:-不可变性:`String`对象一旦被创建,其内容就不能改变。任何对`String`的操作,比如拼接、替换等,都会返回一个新的`String`对象,而原对象保持不变。-性能:由于每次修改都会创建新对象,因此在进行大量字符串操作时可能引起性能问题,尤其是在循环中连续拼接字符串。
2024-05-13 15:18:42
652
原创 hashCode()与equals()之间的关系
在Java中,`hashCode()`和`equals()`方法之间存在紧密的关系,主要体现在它们共同作用于对象的比较和存储上,尤其是在集合(如HashSet、HashMap)和哈希表的实现中。一致性:如果两个对象相等(即`equals()`返回`true`),那么它们的`hashCode()`方法必须返回相同的值。非一致性:对象不相等(`equals()`返回`false`)时,其`hashCode()`可以相同,但这可能会降低哈希表的性能,因为冲突增多可能导致链表长度增加,影响查询效率。
2024-05-13 14:22:49
163
原创 Tomcat中为什么要使用自定义类加载器
这样,即使不同应用中存在相同的类名,它们也是被各自的应用类加载器加载,互不影响。一个,代表Tomcat中用于加载共享类库的类加载器;在方法中,我们展示了如何通过Web应用类加载器加载类,同时这个加载器会委托给共享类加载器,模拟了Tomcat类加载的委托机制。通过创建新的类加载器来加载更新后的类,旧的类加载器和旧的类可以被垃圾回收,实现类的平滑升级。这种层次结构允许类加载器首先在本地查找类,找不到时再委托给父加载器,既保证了类加载的高效性,又确保了类的正确加载顺序,避免了类覆盖问题。中类加载器的委托逻辑。
2024-05-13 11:00:57
341
原创 Sychronized的锁升级过程是怎样的
4.自旋锁∶自旋锁就是线程在获取锁的过程中,不会去阻塞线程,也就无所谓唤醒线程,阻塞和唤醒这两个步骤都是需要操作系统去进行的,比较消耗时间,自旋锁是线程通过CAS获取预期的一个标记,如果没有获取到,则继续循环获取,如果获取到了则表示获取到了锁,这个过程线程一直在运行中,相对而言没有使用太多的操作系统资源,比较轻量。如果成功,线程获得锁;第二个线程来竞争锁,偏向锁就会升级为轻量级锁,之所以叫轻量级锁,是为了和重量级锁区分开来,轻量级锁底层是通过自旋来实现的,并不会阻塞线程。
2024-05-11 17:26:19
763
原创 ReentrantLock分为公平锁和非公平锁,那底层分别是如何实现的
无论是公平锁还是非公平锁,它们都使用了AQS的内部FIFO队列来管理等待的线程,以及通过状态位(state)和等待节点(Node)来协调线程的阻塞与唤醒。如果有其他线程已经在等待队列中,那么新来的线程就会加入到队列的末尾排队等待,而不是尝试直接获取锁。非公平锁在尝试获取锁时,不管队列中是否有其他线程在等待,总是会先尝试直接通过CAS操作快速获取锁,这可能导致新来的线程“插队”,获得锁的机会优于已经在队列中等待的线程。2. 如果快速获取失败,非公平锁仍然可能会继续尝试CAS获取锁,即使队列中已有等待线程。
2024-05-11 16:11:02
795
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人