Java
未读Java并发之AQS源码篇二、完整源码以下源码版本为JDK8。
package java.util.concurrent.locks;import java.util.concurrent.TimeUnit;import java.util.ArrayList;import java.util.Collection;import java.util.Date;import sun.misc.Unsafe;/** * 为实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量、事件等)提供了一个框架。 * 该类被设计为大多数类型的同步器的有用基础,这些同步器依赖于单个原子int值来表示状态。 * 子类必须定义改变这种状态的受保护方法,这些方法定义了该对象被获取或释放时该状态的含义。 * 考虑到这些,这个类中的其他方法执行所有排队和阻塞机制。 * 子类可以维护其他状态字段,但是只有使用getState、setState和compareAndSetState方法操纵的自动更新的int值才会跟踪同步。 * * 子类应该定义为非公共的内部助手类,用于实现其外围类的同步属性。 * 类Abs ...
Java并发之ReentrantLock源码篇一、ReentrantLockReentrantLock 是一个可重入且独占式的锁,和 synchronized 关键字类似。不过,ReentrantLock 更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。
1. 继承关系ReentrantLock实现了Lock接口,Lock接口中定义了lock与unlock相关操作,并且还存在newCondition方法,表示生成一个条件。
public class ReentrantLock implements Lock, java.io.Serializable { ... }
Lock接口主要方法如下:
2. 内部类ReentrantLock总共有三个内部类,并且三个内部类是紧密相关的。
Sync,继承自AbstractQueueSynchronizer抽象类,
FairSync,继承自Sync类
NonfairSync,继承自Sync类
(1) Sync通过下面的源码可以看到,Sync其实就是重写了AbstractQueuedSynchroniz ...
带你学习如何排查和解决OOM在面试的过程中,可能有的小伙伴会被问到:你有遇到过OOM吗?你是如何解决的?
当然,在日常的开发中,我们可能永远也遇不到OOM,哈哈哈,当然,万一碰到了呢,所以大家还是有必要来学习一下OOM以及如何排查。
通过阅读这篇文章,我将带领大家解决以下两个问题:
哪些内存区域会出现OOM?
如何排查和解决OOM?
下面就让我们一起来学习吧~
在《Java虚拟机规范》的规定里,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(下文称OOM)异常的可能。
现在我们解决了第一个问题,除了程序计数器外,虚拟机内存的其他几个运行时区域都会产生OOM异常。那么我们就一起来学习当特定的区域出现了OOM的话应该如何排查和分析。
1. Java堆区溢出Java堆用于储存对象实例,我们只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么随着对象数量的增加,总容量触及最大堆的容量限制后就会产生内存溢出异常。
比如下面这段测试的代码:
import java.util.ArrayList;imp ...
BigDecimal1. 概述Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。
一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。
BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
2. 常用构造函数
BigDecimal(int):创建一个具体参数所指定整数值的对象
BigDecimal(double):创建一个参数所指定双精度值的对象
BigDecimal(long):创建一个参数所指定的 ...
Java
未读JDK81、接口Java8对接口做了进一步的增强。
在接口中添加使用default关键字修饰的非抽象方法,即:默认方法。
接口中可以声明静态方法,并且可以实现 。
默认方法和静态方法:
Java8 允许我们通过default关键字对接口中定义的抽象方法提供一个默认的实现。
public interface MyInterface { // 一个普通的方法 void method(int var); // 一个默认的方法 default void defaultMethod(int var) { System.out.println("执行接口的 default 方法"); } // 一个静态方法 static void staticMethod() { System.out.println("执行接口的 static 方法"); }}
在上面这个接口中,我们除了定义了一个抽象方法 calculat ...
Java
未读Java并发之原子类型源码篇一、Java原子类型当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量 i=1,A 线程更新 i+1,B 线程也更新 i+1,经过两个线程操作之后可能 i 不等于3,而是等于 2。
因为 A 和 B 线程在更新变量 i 的时候拿到的 i 都是 1,这就是线程不安全的更新操作,通常我们会使用 synchronized 来解决这个问题,synchronized 会保证多线程不会同时更新变量 i。
而 Java 从 JDK 1.5 开始提供了 java.util.concurrent.atomic 包(以下简称 Atomic 包),这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。
因为变量的类型有很多种,所以在 Atomic 包里一共提供了 12 个类,属于 4 种类型的原子更新方式,分别是原子更新基本类型、原子更新数组、原子更新引用和原子更新属性(字段)。Atomic 包里的类基本都是使用 Unsafe 实现的包装类。
原子更新基本类型
AtomicBoolean:原子更新布尔类型。
...
分布式事务一、分布式事务问题1.1 本地事务本地事务,也就是传统的单机事务。在传统数据库事务中,必须要满足四个原则:
原子性(A),一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。事务是操作的最小单位,不可再分。
一致性(C),事务发生前和发生后,数据的完整性必须保持一致。
隔离性(I),多个事务之间的数据是相互隔离的,当并发访问数据库时,一个正在执行的事务对其他事务是不可见的。
持久性(D),一个事务一旦被提交或者回滚,它对数据库中数据的改变是永久性的。
1.2 分布式事务分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务,例如:
跨数据源的分布式事务
跨服务的分布式事务
在数据库水平拆分、服务垂直拆分之后,一个业务操作通常要跨多个数据库、服务才能完成。例如电商行业中比较常见的下单付款案例,包括下面几个行为:
创建新订单
扣减商品库存
从用户账户余额扣除金额
完成上面的操作需要访问三个不同的微服务和三个不同的数据库。
订单的创建、库存的扣减、账户扣款在每一个服务和数据库内是一个本地事务,可以保证ACID原 ...
Redis
未读Redisson分布式锁源码篇Redisson 是一个简单的Redis Java客户端,具有内存数据网格功能。
它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。
GitHub地址:https://github.com/redisson/redisson
Redisson分布式锁不仅是相对成熟的分布式锁方案,而且在很多企业中都会去使用的,所以了解一下底层的实现还是很有必要的。
一、使用Redisson分布式锁Redisson分布式锁的使用非常简单,我们只需要在maven中引入依赖,然后直接调用相关API即可。
1.1 引入依赖<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.13.6</version> </dependency>
1.2 调用 ...
Redis
未读Redis分布式锁实现一、分布式锁
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
分布式锁的核心是实现多进程之间互斥,而满足这一点的方式有很多,常见的有三种:
MySQL
Redis
Zookeeper
互斥
利用MySQL本身的互斥锁机制
利用setnx互斥命令
利用节点的唯一性和有序性实现互斥
高可用
好
好
好
高性能
一般
好
一般
安全性
断开连接,自动释放锁
利用锁超时时间,到期释放
临时节点,断开连接自动释放
二、 基于Redis的分布式锁2.1 初级版本实现基于Redis的分布式锁需要实现两个基本的方法:
获取锁
互斥:确保只有一个线程获取锁
// 添加锁,利用setnx的互斥特性setnx lock thread1// 添加锁过期时间,避免服务器宕机引起的死锁expire lock 10
// 添加锁,NX是互斥,EX是设置超时时间set lock thread1 NX EX 10
释放锁
手动释放:删除key即可
超时释放:获取锁时添加一个超时时间
// 释放锁,删除即可del key
基本逻辑 ...
MySQL
未读MySQL深度分页优化问题一、Limit使用limit子句可以用于强制select语句返回指定的记录数。
select 字段 from 表名 limit 参数1,参数2;select 字段 from 表名 limit 参数2 offset 参数1;(为了与 PostgreSQL 兼容)
参数1:指定第一个返回记录行的偏移量,从0开始
参数2:指定返回记录行的最大数目
如果只给定一个参数,那么表示返回的最大记录行数目。
如果第二个参数为-1,表示第一个参数的偏移量之后的所有的数据。
二、深度分页优化查询偏移量过大的场景我们称为深度分页,这会导致查询性能较低。比如下面的查询:
# 普通分页查询test> select * from t_demo order by id limit 1000000, 10[2024-01-18 20:26:41] 在 396 ms (execution: 346 ms, fetching: 50 ms) 内检索到从 1 开始的 10 行
这条SQL在执行的过程中,通过非聚簇索引去查询主键,然后拿到主键再通过聚簇索引进行回表查询,查询到满足条件的 ...