Netty(三) 什么是 TCP 拆、粘包?如何解决?
如何优雅的使用和理解线程池
前言
平时接触过多线程开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴 Java 手册》里也有一条:
可见线程池的重要性。
简单来说使用线程池有以下几个目的:
- 线程是稀缺资源,不能频繁的创建。
- 解耦作用;线程的创建于执行完全分开,方便维护。
- 应当将其放入一个池子中,可以给其他任务进行复用。
线程池原理
谈到线程池就会想到池化技术,其中最核心的思想就是把宝贵的资源放到一个池子中;每次使用都从里面获取,用完之后又放回池子供其他人使用,有点吃大锅饭的意思。
那在 Java 中又是如何实现的呢?
在 JDK 1.5 之后推出了相关的 api,常见的创建线程池方式有以下几种:
Executors.newCachedThreadPool()
:无限线程池。Executors.newFixedThreadPool(nThreads)
:创建固定大小的线程池。Executors.newSingleThreadExecutor()
:创建单个线程的线程池。
HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!
Guava 源码分析(Cache 原理【二阶段】)
前言
在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache
的相关原理。
文末提到了回收机制、移除时间通知等内容,许多朋友也挺感兴趣,这次就这两个内容再来分析分析。
在开始之前先补习下 Java 自带的两个特性,Guava 中都有具体的应用。
Java 中的引用
首先是 Java 中的引用。
在之前分享过 JVM 是根据可达性分析算法找出需要回收的对象,判断对象的存活状态都和引用
有关。
在 JDK1.2 之前这点设计的非常简单:一个对象的状态只有引用和没被引用两种区别。
一次线上问题排查所引发的思考
前言
之前或多或少分享过一些内存模型、对象创建之类的内容,其实大部分人看完都是懵懵懂懂,也不知道这些的实际意义。
直到有一天你会碰到线上奇奇怪怪的问题,如:
- 线程执行一个任务迟迟没有返回,应用假死。
- 接口响应缓慢,甚至请求超时。
- CPU 高负载运行。
这类问题并不像一个空指针、数组越界这样明显好查,这时就需要刚才提到的内存模型、对象创建、线程等相关知识结合在一起来排查问题了。
正好这次借助之前的一次生产问题来聊聊如何排查和解决问题。
生产现象
首先看看问题的背景吧:
我这其实是一个定时任务,在固定的时间会开启 N 个线程并发的从 Redis 中获取数据进行运算。
业务逻辑非常简单,但应用一般涉及到多线程之后再简单的事情都要小心对待。
果不其然这次就出问题了。
现象:原本只需要执行几分钟的任务执行了几个小时都没退出。翻遍了所有的日志都没找到异常。
于是便开始定位问题之路。
Netty(二) 从线程模型的角度看 Netty 为什么是高性能的?
前言
在之前的 SpringBoot 整合长连接心跳机制 一文中认识了 Netty。
但其实只是能用,为什么要用 Netty?它有哪些优势?这些其实都不清楚。
本文就来从历史源头说道说道。
传统 IO
在 Netty 以及 NIO 出现之前,我们写 IO 应用其实用的都是用 java.io.*
下所提供的包。
比如下面的伪代码:
1 | ServeSocket serverSocket = new ServeSocket(8080); |
一个学渣的阿里之路
前言
最近有些朋友在面试阿里,加上 Java-Interview 项目的原因也有小伙伴和我讨论,近期也在负责部门的招聘,这让我想起年初那段长达三个月的奇葩面试经历🤣。
本来没想拿出来说的,毕竟最后也没成。
但由于那几个月的经历让我了解到了大厂的工作方式、对候选同学的考察重点以及面试官的套路等都有了全新的认识。
当然最重要的是这段时间的查漏补缺也让自己精进不少。
先交代下背景吧:
从去年 12 月到今年三月底,我前前后后面了阿里三个部门。
其中两个部门通过了技术面试,还有一个跪在了三面。
光看结果还不错,但整个流程堪称曲折。
下面我会尽量描述流程以及大致的面试题目大纲,希望对想要跳槽、正在面试的同学带来点灵感,帮助可能谈不上,但启发还是能有。
以下内容较长,请再次备好瓜子板凳。
Guava 源码分析(Cache 原理)
前言
Google 出的 Guava 是 Java 核心增强的库,应用非常广泛。
我平时用的也挺频繁,这次就借助日常使用的 Cache 组件来看看 Google 大牛们是如何设计的。
缓存
本次主要讨论缓存。
缓存在日常开发中举足轻重,如果你的应用对某类数据有着较高的读取频次,并且改动较小时那就非常适合利用缓存来提高性能。
缓存之所以可以提高性能是因为它的读取效率很高,就像是 CPU 的 L1、L2、L3
缓存一样,级别越高相应的读取速度也会越快。
但也不是什么好处都占,读取速度快了但是它的内存更小资源更宝贵,所以我们应当缓存真正需要的数据。
其实也就是典型的空间换时间。
下面谈谈 Java 中所用到的缓存。
分布式工具的一次小升级⏫
前言
之前在做 秒杀架构实践 时有提到对 distributed-redis-tool 的一次小升级,但是没有细说。
其实主要原因是:
秒杀时我做压测:由于集成了这个限流组件,并发又比较大,所以导致连接、断开 Redis 非常频繁。
最终导致获取不了 Redis connection 的异常。
池化技术
这就是一个典型的对稀缺资源使用不善导致的。
何为稀缺资源?常见的有:
- 线程
- 数据库连接
- 网络连接等
这些资源都有共同的特点:创建销毁成本较高。