两台4核8g模拟,一台部署中间件和监控、一台部署营销抽奖系统。
一、Tomcat、Mysql、Redis线程池连接配置
抽奖系统是IO密集型,AI推荐
经验法则:每个核心最佳线程数 ≈ 50-150
4核 × 100 = 400(正好在中值)
两台4核8g模拟,一台部署中间件和监控、一台部署营销抽奖系统。
抽奖系统是IO密集型,AI推荐
经验法则:每个核心最佳线程数 ≈ 50-150
4核 × 100 = 400(正好在中值)
在进行系统压测前,需要监控程序情况。今天实践了通过 Prometheus + Grafana 搭建应用监控体系,为后续使用 JMeter 对营销系统抽奖接口进行压测做准备。其中 Prometheus 主要负责指标数据的采集与存储,而 Grafana 则专注于数据的可视化展示。

首先需要在应用程序中集成监控采集能力,让 Spring Boot 应用能够暴露指标数据供 Prometheus 抓取。
当JVM监测到堆内存不足时、手动调用System.gc()时、对象数量或内存使用达到阈值时会进行垃圾回收。
MaxTenuringThreshold(默认15)的对象直接晋升老年代当尝试创建一个对象时,JVM首先会到元空间中查找该对象的类符号引用(可以理解为类的模板信息)。检查这个类是否已经被加载、解析和初始化。如果没有,则会触发完整的类加载过程。
类加载检查通过后,JVM会在堆内存中为新对象划分一块内存空间。具体的内存分配方式取决于垃圾收集器的实现,常见的有:
多线程中需要各个线程自己处理异常,外部线程是无法try-catch捕获异步线程抛出的异常,只能内部线程自己try-catch处理。但是不可能所有都自己处理,有些需要外部处理,搜寻后有几种方法。
Thead确实提供了一个setUncaughtExceptionHandler方法,我们只需要将自定义未捕获异常处理器作为参数传入进入就可以了。
public class ThreadException {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setUncaughtExceptionHandler();
myThread.start();
}
}
class MyThread extends Thread {
@Override
public void run()
{
System.out.println("线程名:" + Thread.currentThread().getName());
//发生异常
int i = 1 / 0;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void setUncaughtExceptionHandler()
{
this.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕获线程抛出的异常:" + e.getMessage());
}
});
}
}
JVM的三大组件是类加载、垃圾回收、运行时数据区。其中运行时数据区主要是如下:
运行时数据区
├── 线程共享区域
│ ├── 堆(Heap) ← 存放对象实例
│ └── 方法区(Method Area) ← 存放类信息、常量、静态变量等
│
└── 线程私有区域(每个线程独立一份)
├── 程序计数器(PC Register)← 当前执行指令地址
├── Java虚拟机栈(JVM Stack)← 方法调用的栈帧
└── 本地方法栈(Native Method Stack)
Redis 提供 5 大基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(哈希)、Zset(有序集合)。其底层实现会根据数据特征智能切换数据结构,以达到性能与内存的最优平衡。
ht[0] 和 ht[1]),扩容时逐步将 ht[0] 的数据迁移到更大的 ht[1]。期间,新写入的数据直接进入 ht[1],查找时会同时检查两个表。迁移完成后释放 ht[0],并将 ht[1] 设置为新的主表。线程池分为核心线程池,线程池的最大容量,还有等待任务的队列,提交一个任务,如果核心线程没有满,就创建一个线程,如果满了,就是会加入等待队列,如果等待队列满了,就会增加线程,如果达到最大线程数量,如果都达到最大线程数量,就会按照一些丢弃的策略进行处理。
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
本文将记录学习到的synchronized底层实现以及Synchronized的锁升级的优化策略。
synchronized是内置锁,使用时以关键字的方式进行使用。在使用synchronized后,底层编译后代码前后会被加上monitorenter和monitorexit字节码指令(无论偏向锁和轻量级锁都会进行这些字节码指令的执行)。

即Blocking IO,同步阻塞通信,每次有新的链接与服务端链接后,服务端链接的线程会阻塞住,一直到通信完后才进行其他线程。
即Non-Blocking IO,同步非阻塞通信,这是基于Selector和Epoll来实现的,Selector代替了线程本身轮询IO事件,避免了阻塞同时减少了不必要的线程消耗。
