🧱 后端开发与架构
未读Java 8 引进了强大的 Stream API,使得集合操作更加简洁优雅。本文将详细介绍如何使用 Java 8 的 Stream API 进行 List 转 Map、List 排序、列表过滤及 Map 中的条件操作。 使用 Java 8 Lambda 将 list 转为 map常用方式要将一个 List 转换为 Map,我们可以利用 Collectors.toMap() 方法。例如: 123public Map<Long, String> getIdNameMap(List<Account> accounts) { return accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsername));} 收集成实体本身 map有时候我们可能希望将列表中的对象直接映射到 Map 中作为值,可以这样做: 123public Map<Long, Account> getIdAccountMap(List<Account&g ...
🧩 开发框架与中间件
未读Zookeeper 是 Google 的 Chubby 一个开源的实现,是 Hadoop 的分布式协调服务 自 2010 年 10 月升级成 Apache Software Foundation(ASF) 顶级项目 分布式协调服务, 提供以下功能: 组管理服务 分布式配置服务 分布式同步服务 分布式命名服务 谁在使用 Zookeeper开源软件 HBase 开源的非关系型分布式数据库 Solr Apache Lucene 项目的开源企业搜索平台 Storm 分布式计算框架 Neo4j 高性能的,Nosql 图形数据库 … 公司 Yahoo LinkedIn Twitter Taobao … Zookeeper 架构 客户端随机连接集群中的任何一台 server 集群内所有的 server 基于 Zab(ZooKeeper Atomic Broadcast) 协议通信 集群内部根据算法自动选举出 leader, 负责向 follower 广播所有变化消息 集群中每个 follower 都和 leader 通信 follower 接收来自 leader 的所有变化 ...
🧱 后端开发与架构
未读Python 面向对象基础部分 中秋在家没事, 写了一个很久以前就想写的脚本 如果下午 6 点 10 分还连接着公司的 wifi, 就发邮件给老婆说要加班 为什么要发邮件而不发短信呢, 因为短信接口要钱….最近买了个 4k 的显示器, 拿来外接 mac 看代码, 爽翻了, 不过有点蛮烦的就是每次都要拖动鼠标到另一个屏幕上去, 不过全国最大的同性交友网站 GitHub上面有一款开源的软件叫 CatchMouse 解决了这个问题 下载地址: CatchMouse 另一个问题是如果想把软件从 mac 屏幕放到外接显示屏的话, 还是要拖过去, 但是….另一款神器 Moon 能帮我们快速的把当前应用移动到外接显示器上, 光标定位到需要移动的 app 上, 快捷键 contro+` 即可 接下来是脚本 我的思路是: 先检测当前连接的是哪里的 wifi如果是公司的 wifi, 且当前时间大于 6 点 10 分, 则给老婆发送邮件如果连接的是家里的 wifi, 则检测是否连接了外接显示器,如果连接了, 则检测是否开启了 CatchMouse.app, 没有则打开. 接下来开始撸代 ...
ERROR: Permission to ArrayDsj/git-test.git denied to dong4j.fatal: Could not read from remote repository. Please make sure you have the correct access rightsand the repository exists. 目前有 2 个 github 账号, 一个公司的 gitlab 账号 有一次遇到了 1ERROR: Permission to XXX.git denied to user 错误, 整理了一下,这里做一个记录 错误前提很久以前使用 ssh-keygen 生成一对默认名称的公私匙, 直接导入 github 中就能使用, 这是只在一个用户的情况下, 后台又申请了一个 github 账号, 还是使用 id_rsa.pub 这个默认的公匙, 这就造成了上面的错误. 解决方法为不同的账号生成不同的公私匙 1. 生成密匙对 1234567891011# 生成密匙对 名称为 user1-github-ssh-k ...
🧱 后端开发与架构
未读当程序使用某个类时, 如果该类还没被初始化, 加载到内存中, 则系统会通过加载、连接、初始化三个过程来对该类进行初始化. 该过程就被称为类的初始化 类加载指将类的 class 文件读入内存, 并为之创建一个 java.lang.Class 的对象 类文件来源 从本地文件系统加载的 class 文件 从 JAR 包加载 class 文件 从网络加载 class 文件 把一个 Java 源文件动态编译, 并执行加载 类加载器通常无须等到“首次使用”该类时才加载该类, JVM 允许系统预先加载某些类 类加载器类加载器就是负责加载所有的类, 将其载入内存中, 生成一个 java.lang.Class 实例. 一旦一个类被加载到 JVM 中之后, 就不会再次载入了. 根类加载器(Bootstrap ClassLoader): 其负责加载 Java 的核心类, 比如 String、System 这些类 拓展类加载器(Extension ClassLoader): 其负责加载 JRE 的拓展类库 系统类加载器(System ClassLoader): 其负责加载 CLA ...
介绍 Java 内存模型 3 大核心 原子性 可见性 顺序性 原文出处 https://segmentfault.com/a/1190000000435392 并发编程模型的分类在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。 在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写 - 读内存中的公共状态来隐式进行通信。在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信。 同步是指程序用于控制不同线程之间操作发生相对顺序的机制。在共享内存并发模型里,同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。 Java 的并发采用的是共享内存模型,Java 线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。如果编写多线程程序的 Java程序员不理解隐式 ...
🧩 开发框架与中间件
未读“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。 同步调用下面通过一个简单示例来直观的理解什么是同步调用: 定义 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 ...
















