🧩 开发框架与中间件
未读“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。 同步调用下面通过一个简单示例来直观的理解什么是同步调用: 定义 Task 类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10 秒内) 123456789101112131415161718192021222324252627@Componentpublic class Task { public static Random random =new Random(); public void doTaskOne() throws Exception { System.out.println("开始做任务一"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); ...
🧩 开发框架与中间件
未读我们在工作中有时候可能会遇到这样场景,需要在退出容器的时候执行某些操作。SpringBoot 中有两种方法可以供我们来选择(其实就是 spring 中我们常用的方式。只是 destory-method 是在 XML 中配置的,SpringBoot 是去配置化。所以这里就不提这种方式了),一种是实现 DisposableBean 接口,一种是使用@PreDestroy 注解。OK,下面我写两个例子看一下: DisposableBean 接口我们可以通过实现这个接口来在容器退出的时候执行某些操作。例子如下: 123456789101112131415161718@Componentpublic class TestImplDisposableBean implements DisposableBean, ExitCodeGenerator { @Override public void destroy() throws Exception { System.out.println("<<<<<&l ...
🧩 开发框架与中间件
未读在大部分时候,我们讨论 API 的设计时,会从功能的角度出发定义出完善的,易用的 API。而很多时候,非功能需求如安全需求则会在很晚才加入考虑。而往往这部分会涉及很多额外的工作量,比如与外部的 SSO 集成,Token 机制等等。 这篇文章会以一个简单的例子,从应用程序和部署架构上分别讨论几种常见的模型。这篇文章是这个系列的第一篇,会讨论两个简单的主题: 基于 Session 的用户认证 基于 Token 的 RESTful API(使用 Spring Security) 使用 Session由于 HTTP 协议本身是无状态的,服务器需要某种机制来区分每个请求。比如在返回给客户的响应中加入一些 ID,客户端再次请求时带上这个 ID,这样服务器就可以区分出来每个请求,并完成事务性的操作(完成订单的创建,更新,商品派送等等)。 在多数 Web 容器中,这种机制通过 Session 来实现。Web 容器会为每个首次请求创建一个 Session,并将 Session 的 ID 以浏览器 Cookie 的方式返回给客户端。客户端(常常是浏览器)在后续的请求中带上这个 Session ...
🧱 后端开发与架构
未读写 Java 程序时会经常从 classpath 下读取文件, 是时候该整理一下了, 并在不断深入的过程中, 陆续补充上. 现在 Java project 都以 maven 项目居多, 比如像下面这样的一个项目结构: 编译后的 class 文件都到了 target 目录, 如下面的结构: 看代码: 123456789101112131415161718192021222324import java.io.File;import java.net.URL;public class Poem { public static void main(String[] args) { Poem poem = new Poem(); poem.getFile("extObj.txt"); } private void getFile(String fileName) { ClassLoader classLoader = getClass().getClassLoa ...
🧱 后端开发与架构
未读有时候,系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新线程的话,系统就要不断的进行线程的创建和销毁,有时花在创建和销毁线程上的时间会比线程真正执行的时间还长。而且当线程数量太多时,系统不一定能受得了。 使用线程池主要为了解决一下几个问题: 通过重用线程池中的线程,来减少每个线程创建和销毁的性能开销。 对线程进行一些维护和管理,比如定时开始,周期执行,并发数控制等等。 ExecutorExecutor 是一个接口,跟线程池有关的基本都要跟他打交道。下面是常用的 ThreadPoolExecutor 的关系。 Executor 接口很简单,只有一个 execute 方法。 ExecutorService 是 Executor 的子接口,增加了一些常用的对线程的控制方法,之后使用线程池主要也是使用这些方法。 AbstractExecutorService 是一个抽象类。ThreadPoolExecutor 就是实现了这个类。 ThreadPoolExecutor构造方法ThreadPoolExecutor 是线程池的真正实现,他通过构造方法的一系列参数,来构 ...
🧱 后端开发与架构
未读总结线程池的使用方式 Java 通过 Executors 提供四种线程池, 分别为: newCachedThreadPool 创建一个可缓存线程池, 如果线程池长度超过处理需要, 可灵活回收空闲线程, 若无可回收, 则新建线程. newFixedThreadPool 创建一个定长线程池, 可控制线程最大并发数, 超出的线程会在队列中等待. newScheduledThreadPool 创建一个定长线程池, 支持定时及周期性任务执行. newSingleThreadExecutor 创建一个单线程化的线程池, 它只会用唯一的工作线程来执行任务, 保证所有任务按照指定顺序 (FIFO, LIFO, 优先级) 执行. 线程池比较单线程的优势在于: 重用存在的线程, 减少对象创建、消亡的开销, 性能佳. 可有效控制最大并发线程数, 提高系统资源的使用率, 同时避免过多资源竞争, 避免堵塞. 提供定时执行、定期执行、单线程、并发数控制等功能. newCachedThreadPool 12345678910111213141516public static void main( ...
🧱 后端开发与架构
未读在 Java 中, GC 的对象是堆空间和永久区 引用计数算法 Java 不再使用 Python,COM,ActionScript3 使用 性能差 不能解决循环引用问题 标记 - 清除算法标记阶段在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象 清除阶段清除所有未被标记的对象 标记 - 压缩算法 标记 - 压缩算法适合用于存活对象较多的场合,如老年代.它在标记 - 清除算法的基础上做了一些优化. 标记阶段从根节点开始,对所有可达对象做一次标记 压缩阶段将所有存活对象压缩到内存一端, 然后清除边界外的所有空间 复制算法 与标记 - 清除算法相比, 复制算法是一种相对高效的回收方式 不适合存活对象较多的场合, 如老年代 将原来的内存分为相同大小的两块, 每次只是用其中一块, 在垃圾回收时, 将正在是用的内存中的对象复制到未使用的内存块中, 之后清除正在是用的内存中的所有对象,交换两个内存的角色, 完成垃圾回收 问题: 空间浪费, 只是用了一半 是用标记清理和复制算法配置回收垃圾 在最上面那块大的区域产生新对象。 大对象不太适合在复制空间,因为复制空间的 ...
🧱 后端开发与架构
未读volatile 关键字的 2 个语义 内存可见性 阻止重排序 volatile 不能保证原子性 volatile 关键字的 2 层含义: 用 volatile 修饰的变量, 线程在每次使用变量的时候, 都会读取变量修改后的最新的值.作为指令关键字, 确保本条指令不会因编译器的优化而省略, 且要求每次直接读值. 可见性可见性是指 当一个线程修改了一个共享变量, 其他线程能够立刻得知这个修改.这里有必要了解一下 Java 的内存模型 被 volatile 修饰的变量, 当线程需要使用这个变量时, 回去主内存中读取, 然后加载到自己的工作线程中,工作线程中的变量只是主存变量的一个拷贝, 当使用完这个变量后, 会刷新会主存中. 当数据中主内存复制到工作内存存储时, 必须出现两个动作: 由主内存执行的 read 操作 有工作内存执行相应的 load 操作 当数据从工作内存拷贝到主内存时, 也会有两个操作: 用工作内存执行的 store 操作 用主内存执行相应的 write 操作 volatile 的特殊规则就是 read、load、use 必须连续出现. assig ...
🧱 后端开发与架构
未读生产者消费者问题是研究多线程程序时绕不开的经典问题之一, 它描述是有一块缓冲区作为仓库, 生产者可以将产品放入仓库, 消费者则可以从仓库中取走产品 生产者消费者问题生产者消费者问题是研究多线程程序时绕不开的经典问题之一, 它描述是有一块缓冲区作为仓库, 生产者可以将产品放入仓库, 消费者则可以从仓库中取走产品.解决生产者 / 消费者问题的方法可分为两类: 采用某种机制保护生产者和消费者之间的同步; 在生产者和消费者之间建立一个管道. 第一种方式有较高的效率, 并且易于实现, 代码的可控制性较好, 属于常用的模式. 第二种管道缓冲区不易控制, 被传输数据对象不易于封装等, 实用性不强. 同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用信号或加锁机制, 保证资源在任意时刻至多被一个线程访问.Java 语言在多线程编程上实现了完全对象化, 提供了对同步机制的良好支持.在 Java 中一共有五种方法支持同步, 其中前四个是同步方法, 一个是管道方法. wait()/ notify() 方法 await()/ s ...
🧱 后端开发与架构
未读几个多线程概念的介绍 线程状态转换 新建 (new): 新创建一个线程对象 可运行 (runnable):线程对象创建后,其他线程(比如 main 线程)调用了该对象的 start() 方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。 运行 (running):可运行状态(runnable) 的线程获得了 cpu 时间片(timeslice) ,执行程序代码。 阻塞 (block):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice,暂时停止运行。直到线程进入可运行(runnable) 状态,才有机会再次获得cpu timeslice 转到运行 (running) 状态。阻塞的情况分三种: 等待阻塞:运行 (running) 的线程执行 o.wait()方法,JVM 会把该线程放入等待队列 (waitting queue) 中。 同步阻塞:运行 (running) 的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池 (lock pool) 中。 其他阻塞:运行 (ru ...
🧱 后端开发与架构
未读总结方法区和运行时常量池 相关特征方法区特征 同 Java 堆一样, 方法区也是全局共享的一块内存区域 方法区的作用是存储 Java 类的结构信息, 当我们创建对象实例后, 对象的类型信息存储在方法堆之中, 实例数据存放在堆中;实例数据指的是在 Java中创建的各种实例对象以及它们的值, 类型信息指的是定义在 Java代码中的常量、静态变量、以及在类中声明的各种方法、方法字段等等;同事可能包括即时编译器编译后产生的代码数据. JVMS 不要求该区域实现自动的内存管理, 但是商用 JVM 一般都已实现该区域的自动内存管理. 方法区分配内存可以不连续, 可以动态扩展. 该区域并非像 JMM 规范描述的那样数据一旦放进去就属于 “永久代”; 在该区域进行内存回收的主要目的是对常量池的回收和对内存数据的卸载;一般来说这个区域的内存回收效率比起Java 堆要低得多. 当方法区无法满足内存需求时, 将抛出 OutOfMemoryError 异常. 运行时常量池的特征 运行时常量池是方法区的一部分, 所以也是全局共享的. 其作用是存储 Java 类文件常量池中的符号信息. cl ...
🧱 后端开发与架构
未读几个并发概念的介绍 同步(synchronous)和异步(asynchronous) 同步调用会等待方法的返回, 异步调用会马上返回, 但是异步调用返回并不代表人任务已经完成, 它会在后台启个线程继续进行任务 并发(Concurrency)和并行(Parallelism) 并发和并行在外在表象来说, 是差不多的. 由图所示, 并行则是两个任务同时进行, 而并发呢, 则是一会做一个任务一会又切换做另一个任务. 所以单个 cpu是不能做并行的, 只能是并发. 临界区 临界区用来表示一种公共资源或者说是共享数据, 可以被多个线程使用, 但是每一次, 只能有一个线程使用它, 一旦临界区资源被占用, 其他线程要想使用这个资源,就必须等待. 阻塞(Blocking)和非阻塞(Non-Blocking) 阻塞和非阻塞通常用来形容多线程间的相互影响. 比如一个线程占用了临界区资源, 那么其它所有需要 这个资源的线程就必须在这个临界区中进行等待,等待会导致线程挂起. 这种情况就是阻塞. 此时, 如 果占用资源的线程一直不愿意释放资源, 那么其它所有阻塞在这个临界区上的线程都不 ...
🔥 效能提升
未读本文将带你深入了解 tmux 的基本操作和使用技巧,让你能够更高效地使用终端。我们将从安装、配置、常用命令以及插件等方面进行详细介绍。 一、什么是 tmux?tmux 是一个终端复用软件,它可以将多个终端窗口合并到一个窗口中,从而提高工作效率。简单来说,它可以让你在一个终端窗口中同时打开多个会话(session)、窗口(window)和面板(panel),并进行自由切换和管理。 二、安装与配置 安装 123git clone https://github.com/gpakosz/.tmux.git .oh-my-tmuxln -s -f .oh-my-tmux/.tmux.conf ~/.tmux.confcp .oh-my-tmux/.tmux.conf.local ~/.tmux.conf.local 插件安装 1git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm 三、常用命令 会话管理 新建会话:tmux new -s my_session_name 切换会话:tmux at - ...
🔥 效能提升
未读Homebrew 是 macOS 和 Linux 上的包管理器,允许用户通过命令行轻松安装、更新和管理软件包。它极大地简化了软件包的获取和维护过程,尤其适合开发者。本文将深入探讨 Homebrew 的功能、安装方式、核心命令以及一些进阶用法,帮助你快速上手并高效管理开发环境。 什么是 Homebrew?Homebrew 是一个开源项目,由 Max Howell 在 2009 年发布,旨在为 macOS 用户提供类似 Linux 包管理器的体验。Homebrew 的设计哲学是“将复杂的事情简单化”,它能自动解决依赖关系并优化安装过程,为开发者提供了一种轻量级、无 GUI 的方式来安装各种开发工具。现在,Homebrew 也扩展支持了 Linux 系统,使其成为跨平台的工具。 为什么使用 Homebrew?macOS 自带的系统工具和开发环境比较有限,Homebrew 通过一系列命令行工具简化了软件包的安装和管理流程,为 macOS 和 Linux 用户提供了一套完善的包管理方案。相比于手动下载和配置软件,Homebrew 能自动配置依赖项、路径和更新管理等工作,让用户可以专注于开 ...















