特性 | Synchronized | Lock(如ReentrantLock) |
---|---|---|
锁类型 | JVM内置锁(关键字) | JDK接口实现(如ReentrantLock ) |
获取/释放 | 自动获取和释放(进入/退出代码块) | 必须手动lock() 和unlock() (配合try-finally) |
灵活性 | 不灵活(仅非公平锁) | 可公平/非公平、可尝试获取、可超时 |
中断响应 | 不支持线程中断 | 支持lockInterruptibly() |
条件队列 | 单一等待队列 | 支持多个Condition (精准唤醒线程) |
首先,ReentrantLock是一种可重入的排它锁,主要用来解决多线程对共享资源竞争的
问题。
它的核心特性有几个:
- 它支持可重入
,也就是获得锁的线程在释放锁之前再次去竞争同一把锁的时候,不
需要加锁就可以直接访问。
- 它支持公平和非公平特性
- 它提供了阻塞竞争锁和非阻塞竞争锁的两种方法,分别是lock()和tryLock()。
- 锁的竞争,ReentrantLock是通过互斥变量,使用CAS机制来实现的。
- 没有竞争到锁的线程,使用了AbstractQueuedSynchronizer这样一个队列同步器来存储,底层是通过双向链表来实现的。当锁被释放之后,会从AQS队列里面的头部唤醒下一个等待锁的线程。
- 公平和非公平的特性,主要是体现在竞争锁的时候,是否需要判断AQS队列存在等待中的线程。
最后,关于锁的重入特性,在AQS里面有一个成员变量来保存当前获得锁的线程,当同一个线程下次再来竞争锁的时候,就不会去走锁竞争的逻辑,而是直接增加重入次数。
可重入锁是允许同一线程多次获取同一把锁的同步机制。核心在于锁内部通过计数器记录获取次数:首次获取时计数器置 1,重入时递增,释放时递减至 0 才彻底释放锁。
在 Java 中,默认方法(Default Methods) 和 静态方法(Static Methods) 是接口(Interface)的两种扩展特性,它们的作用分别是:
1. 默认方法(Default Methods)
- 作用:
允许在接口中定义具有方法体的方法,为接口提供默认实现,同时不破坏实现类的兼容性。
- 核心优势:
在不强制所有实现类重写方法的情况下,向现有接口添加新功能(如 Java 8 的 Collection 接口添加 forEach 方法)。类可以实现多个接口并继承它们的默认方法(需处理方法冲突)。
2. 静态方法(Static Methods)
- 作用:
为接口提供工具类方法,无需创建实例即可调用,增强接口的功能性。
- 核心优势:
将与接口相关的静态工具方法集中在接口中,避免额外的工具类(如 Collections → Collection)。使代码结构更清晰,工具方法与接口语义绑定。
一句话概括
默认方法:让接口可以提供默认实现,允许接口在不破坏现有实现类的前提下扩展功能;
静态方法:让接口能够包含工具类方法,无需实例化即可调用,使接口兼具行为定义和工具封装能力。
反射是一种允许程序在运行时检查和操作类、接口、字段和方法的机制。通过反射,可以动态地获取类的信息、创建对象、调用方法、访问字段等。
Java 反射的优点:
(1).增加程序的灵活性,可以在运行的过程中动态对类进行修改和操作。
(2).提高代码的复用率,比如动态代理,就是用到了反射来实现。
(3).可以在运行时轻松获取任意一个类的方法、属性,还能通过反射进行动态调用。
Java反射的缺点:
(1).反射会涉及到动态类型解析,所以JVM无法对这些代码进行优化,导致性能要比非反射调用更低。
(2).使用反射以后,代码的可读性会下降。
(3).反射可以绕过一些限制访问的属性或者方法,可能会导致破坏了代码本身的抽象性。
(1).继承 Thread 类并重写 run 方法创建线程,实现简单但不可以继承其他类
(2).实现 Runnable 接口并重写 run 方法。避免了单继承局限性,编程更加灵活,实现解耦。
(3).实现 Callable 接口并重写 call 方法,创建线程。可以获取线程执行结果的返回值,并且可以抛出异常。
(4).使用线程池创建(使用 java.util.concurrent.Executor 接口)
线程池任务提交流程:
(1).核心线程创建阶段
当线程池接收到新任务时,首先检查当前运行的线程数量。
(2).若线程数量少于corePoolSize(核心线程数),无论其他线程是否处于空闲状态,都会立即创建一个新的核心线程来处理该任务。
(3).任务队列缓存阶段
若当前线程数量已达到或超过corePoolSize(核心线程数),新任务将被放入workQueue(工作队列)中等待处理。
(4).临时线程创建阶段
若任务队列已满(如队列达到最大容量),且当前线程数量仍少于maximumPoolSize(最大线程数),则会创建临时线程(非核心线程)来处理新任务。
临时线程在处理完任务后,若在keepAliveTime(线程空闲时间)内没有新任务,将被销毁。
(5).拒绝策略触发阶段
若线程数量已达到maximumPoolSize(最大线程数)且任务队列已满,此时新提交的任务将触发拒绝策略。
线程池的拒绝策略:
(1).AbortPolicy(抛出一个异常,默认的)
(2).DiscardPolicy( 直接丢弃任务 )
(3).DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)
(4).CallerRunsPolicy(交给线程池调用所在的线程进行处理)