线程活跃性问题
线程活跃性问题概述理想情况下,我们希望线程能一直处于运行(Runnable)状态,但是会由于一些因素。这些由于资源稀缺或者程序自身问题导致线程无法一直处于 Runnable 状态运行下去,又或者因为线程处于 Runnable 状态但是其要执行的任务一直无法进展的现象就被称为线程活跃性问题或活性故障。
死锁死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
例如:
1234567891011121314151617181920public static void main(String[] args) { Object lockA = new Object(); Object lockB = new Object(); new Thread(()->{ synchronized (lockA){ System.out.println(" ...
Java进程线程
进程与线程基础概念并发(concurrent):是同一时间应对(dealing with)多件事情的能力并行(parallel):是同一时间动手做(doing)多件事情的能力
同步:需要等待结果返回,才能继续运行
异步:不需要等待结果返回,就能继续运行
进程概念
程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的。
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐等)。
线程概念
一个进程之内可以分为一到多个线程。
一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行
Java 中,线程作为最小调度单位,进程作为资源分配的最小单位。 在 windows 中进程是不活动的,只是作为线程的容器北
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序 ...
Java内存模型
Java内存模型概述JMM即 Java Memory Model,它定义了主存、工作内存抽象概念。
底层对应着复杂的优化:
CPU 增加了缓存,以均衡与内存的速度差异;
操作系统增加了进程、线程,以分时复用 CPU,进而均衡 CPU 与 I/O 设备的速度差异;
编译程序优化指令执行次序,使得缓存能够得到更加合理地利用。
引发的问题体现在以下几个方面:
原子性:保证指令不会受到线程上下文切换的影响
可见性:保证指令不会受cpu缓存的影响
有序性:保证指令不会受cpu指令并行优化的影响
原子性原子性是指一个操作或者多次操作是不可中断的。即使在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。
例如:两个线程对同一个变量进行修改。
12345678910111213141516171819202122232425262728293031public class 原子性 { static int t = 100; public static void main(String[] args) { // 减少t n ...
Reactor模式
Reactor 模式前言
针对传统阻塞 I/O 服务模型的 2 个缺点:
当并发数很大,就会创建大量的线程,占用很大系统资源
连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在 Handler对象中的read 操作,导致上面的处理线程资源浪费
Reactor 模式的解决方案:本质就是I/O多路复用
多个连接共用一个阻塞对象ServiceHandler,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。
当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。
概述Reactor 模式也叫 Dispatcher 模式,即 I/O 多路复用监听事件,收到事件后,根据事件类型分配(Dispatch)给某个线程。
核心组件:
Reactor(也就是那个ServiceHandler):
Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理线程来对 IO 事件做出反应。
Handlers(处理线程EventHandler):
处理线程执行 I/O 事件要完成的实际事件。
分类:
单 Reactor 单线程
...
JWT认证
JWT认证概念JWT(JSON Web Token)是一种用于认证和授权的开放标准;是一个经过加密的,包含用户信息的且具有时效性的固定格式字符串,通常用于在不同的系统之间安全地传递声明(claims)。
JWT 由三部分组成:
头部(Header):头部通常包含了两部分信息,令牌的类型(JWT)和所使用的签名算法(例如 HMAC SHA256 或 RSA)。
载荷(Payload):载荷包含了一系列声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:
注册声明(Registered Claims):这些是一组预定义的声明,包括 iss(签发者)、sub(主题)、aud(受众)、exp(到期时间)、nbf(生效时间)和iat(签发时间)等。
私有声明(Private Claims):这些声明是应用程序特定的,通常用于在双方之间共享信息。
公共声明(Public Claims):这些声明是可选的,可以按需要添加到令牌中。
签名(Signature):签名用于验证令牌的真实性和完整性。它是通过将头部和载荷进行签名生成的,使用密钥来生成签名。验证方可 ...
零拷贝
零拷贝概述所谓的【零拷贝】,并不是真正无拷贝,而是在不会拷贝重复数据到 jvm 内存中。
零拷贝的优点有:
更少的用户态与内核态的切换
不利用 cpu 计算,减少 cpu 缓存伪共享
零拷贝适合小文件传输
前言传统的IO操作,例如一个文件的传输:
12345RandomAccessFile file = new RandomAccessFile(new File("data.txt"), "r");byte[] buf = new byte[1024*1024];file.read(buf);// 以流的形式进行网络传输socket.getOutputStream().write(buf);
数据拷贝流程:
java 本身并不具备 IO 读写能力,需要利用操作系统来完成,因此 read 方法调用后,要从 java 程序的用户态切换至内核态,去调用操作系统(Kernel)的读能力,将数据读入内核缓冲区。这期间用户线程阻塞,操作系统使用 DMA(Direct Memory Access)来实现文件读,其间也不会使用 cpu。
DMA 也可以 ...
Java基础编程优化
Java基础编程调优前言JDK 是 Java 语言的基础库,熟悉 JDK 中各个包中的工具类,可以帮助你编写出高性能代码。但是一些基本类不正确使用会有个别的性能问题,需要去注意去调优。
字符串的性能调优String 对象是我们使用最频繁的一个对象类型,但它的性能问题却是最容易被忽略的。
结果变化:
每次更新就都是为了能够节约内存,提高性能
不可变性:
String 类被 final 关键字修饰了,而且变量 char 数组也被 final 修饰了。而 char[] 被 final+private 修饰,代表了 String 对象不可被更改。
这样的好处是为了能够将创建过的字符串缓存在字符串常量池中,以提供给后面的相同字符串引用。
代码优化
多使用StringBuilder和StringBuffer:
例如:String str= "ab" + "cd" + "ef";
理论上首先会生成 ab 对象,再生成 abcd 对象,最后生成 abcdef 对象,但是编译器底层做了优化:
使用StringBuilder来进行拼接,但 ...
DDD设计流程
设计流程战略设计战略设计是根据用户旅程分析,找出领域对象和聚合根,对实体和值对象进行聚类组成聚合,划分限界上下文,建立领域模型的过程。
战略设计采用的方法是事件风暴,包括:产品愿景、场景分析、领域建模和微服务拆分等几个主要过程。
产品愿景事件风暴时,所有参与者针对每一个要点,在贴纸上写出自己的意见,贴到白板上。事件风暴主持者会对每个贴纸,讨论并对发散的意见进行收敛和统一,形成产品愿景图。
产品愿景分析对于初创系统明确系统建设重点,统一团队建设目标和建立通用语言是很有价值的。但如果你的系统目标和需求非常清晰,这一步可以忽略。
场景分析场景分析是从用户视角出发,探索业务领域中的典型场景,产出领域中需要支撑的场景分类、用例操作以及不同子域之间的依赖关系,用以支撑领域建模。
方法:
项目团队成员一起用事件风暴分析,根据不同角色的旅程和场景分析,尽可能全面地梳理从前端操作到后端业务逻辑发生的所有操作、命令、领域事件以及外部依赖关系等信息。
例如:
领域建模领域建模是通过对业务和问题域进行分析,建立领域模型。向上通过限界上下文指导微服务边界设计,向下通过聚合指导实体对象设计。
步骤:
找 ...
DDD领域模型基础
领域驱动设计(DDD)概述DDD 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。
按照 DDD 方法设计出的微服务的业务和应用边界都非常合理,可以很好地实现微服务内部和外部的“高内聚、低耦合”。
为什么 DDD 适合微服务?
DDD 不是架构,而是一种架构设计方法论,它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现架构演进。
相关名词
领域和子域:
在研究和解决业务问题时,DDD 会按照一定的规则将业务领域进行细分,当领域细分到一定的程度后,DDD 会将问题范围限定在特定的边界内,在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。
DDD 的领域就是这个边界内要解决的业务问题域,而子域就是领域再细分,对应一个更小的问题域或更小的业务范围。
每一个细分的领域都会有一个知识体系,也就是 DDD 的领域模型。
核心域、通用域和支撑域:
子域可以根据自身重要性和功能属性划分为三类子域,它们分别是:核心域、通用域和支撑域。
核心域:决定产品和公司核心竞争力的子域是核心域,它是 ...
Redis6.0新特性
Redis6.0新特性从单线程处理网络请求到多线程处理在之前Redis 一直被大家熟知的就是它的单线程架构,虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写),但是,从网络 IO 处理到实际的读写命令处理,都是由单个线程完成的。
但是后来硬件的发展,单个主线程处理网络请求的速度跟不上底层网络硬件的速度。
Redis6.0为了解决这个问题,采用了多个 IO 线程来处理网络请求,提高网络请求处理的并行度的方案。但是,Redis 的多 IO 线程只是用来处理网络请求的,对于读写命令,Redis 仍然使用单线程来处理。
具体多个IO线程的使用是在解析请求以及写会响应的阶段(利用并行提高速度):
相关设置:
开启多线程:io-threads-do-reads yes
设置多线程数量:io-threads 6(一般来说,线程个数要小于 Redis 实例所在机器的 CPU 核个数,例如,对于一个 8 核的机器来说,Redis 官方建议配置 6 个 IO 线程。)
实现服务端协助的客户端缓存和之前的版本相比,Redis 6.0 新增了一个重要的特性,就是实 ...