优化Tomcat线程池配置
线程池是Tomcat处理并发请求的核心资源,合理配置可平衡并发能力与系统负载。需调整的关键参数包括:
server.xml的Connector中添加):<Connector port="8080" protocol="HTTP/1.1"
maxThreads="300"
minSpareThreads="50"
acceptCount="450"
connectionTimeout="20000"/>
选择高性能连接器协议
Tomcat默认的BIO(阻塞IO)连接器性能有限,高并发场景建议切换至NIO(非阻塞IO)或APR(基于Apache Portable Runtime的高性能连接器):
server.xml中修改protocol):<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" .../>
调整JVM参数优化内存与GC
合理的JVM配置可减少GC停顿,提升Tomcat处理并发的能力:
-XX:+UseG1GC启用,相比CMS可减少停顿时间;-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m,避免元空间溢出。catalina.sh或setenv.sh中添加):export JAVA_OPTS="-server -Xms4g -Xmx4g -XX:+UseG1GC -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
优化Linux内核参数
Linux内核参数直接影响Tomcat的网络与文件处理能力,需调整以下关键参数:
/etc/security/limits.conf(添加* soft nofile 65535和* hard nofile 65535),并通过ulimit -n 65535临时生效;/etc/sysctl.conf,增加TCP缓冲区(net.core.rmem_max=1310720、net.core.wmem_max=1310720)、开启SYN Cookie防止DDoS(net.ipv4.tcp_syncookies=1)、复用TIME_WAIT连接(net.ipv4.tcp_tw_reuse=1),提升网络吞吐量。sysctl -p使配置生效。代码层面优化并发处理
避免应用层代码成为并发瓶颈,需注意以下几点:
synchronized关键字或ReentrantLock保护共享资源(如计数器、缓存),优先选择ReentrantLock(支持公平锁、可中断锁);ConcurrentHashMap、CopyOnWriteArrayList等线程安全集合,减少同步开销;private int count),尽量使用局部变量(如方法内的int localCount),因为Servlet是单例多线程的,全局变量会导致线程不安全。public class SafeCounter {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
使用异步处理释放线程
对于长时间运行的任务(如调用第三方API、大数据处理),使用异步处理避免占用Tomcat线程:
request.startAsync()启动异步上下文,将任务提交至线程池处理,完成后通过AsyncContext返回响应;@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
private ExecutorService executor = Executors.newFixedThreadPool(50);
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
AsyncContext asyncContext = request.startAsync();
executor.submit(() -> {
// 耗时任务
String result = doLongTask();
asyncContext.getResponse().getWriter().write(result);
asyncContext.complete();
});
}
}
监控与诊断并发问题
持续监控Tomcat并发状态,及时发现并解决问题:
jstack命令生成线程转储(如jstack -l <pid> > thread_dump.txt),分析是否存在死锁(查找“Found one Java-level deadlock”)、线程阻塞等问题;server.xml中配置AccessLogValve),统计HTTP状态码(如5xx错误可能表示线程池耗尽)、请求响应时间,识别慢请求。jstack -l $(pgrep -f tomcat) > /tmp/thread_dump_$(date +%F_%H-%M-%S).txt