国内flash网站,手机网站商场建设,企业门户网站解决方案,wordpress头部修改最近项目一个项目要结项了#xff0c;但客户要求 TPS 能达到上千#xff0c;而用我写的代码再怎么弄成只能达到 30 的 TPS#xff0c;然后我又将代码中能缓存的都缓存了#xff0c;能拆分的也都拆分了#xff0c;拆分时用的线程池来实现的#xff1b;其实现的代码主要为… 最近项目一个项目要结项了但客户要求 TPS 能达到上千而用我写的代码再怎么弄成只能达到 30 的 TPS然后我又将代码中能缓存的都缓存了能拆分的也都拆分了拆分时用的线程池来实现的其实现的代码主要为以前写的一篇博客中的实现方式来实现的。如下多线程之 futureTask(future,callable) 实例, jdbc 数据多线程查询https://blog.csdn.net/puhaiyang/article/details/78041046在其中用到了线程池为了方便线程池是采用如下代码 new 出来的final ExecutorService executorService Executors.newFixedThreadPool(10); 通过自己仔细想想后感觉这代码总有哪里写得不对为此特意写了下 DEMO 代码来并用 jmeter 自己跑一下自己测下 RequestMapping(value doTest) public Object doTest(RequestParam(defaultValue false) Boolean shutdown, RequestParam(defaultValue 10) Integer threadCount, RequestParam(defaultValue 100) Integer sleepTime, RequestParam(defaultValue 10) Integer queryCount) { long beginTime System.currentTimeMillis(); final ExecutorService executorService Executors.newFixedThreadPool(threadCount); for (int i 0; i int finalI i; Callable callable new Callable() { Override public Integer call() throws Exception { Thread.sleep(sleepTime); logger.debug(index:{} threadInfo:{}, finalI, Thread.currentThread().toString());return finalI; } }; FutureTask futureTask new FutureTask(callable); executorService.submit(futureTask); }if (shutdown) { executorService.shutdown(); } Long endTime System.currentTimeMillis(); endTime endTime - beginTime; logger.info(info:{}, endTime);return atomicInteger.addAndGet(endTime.intValue()) this: endTime; } 代码如上所示然后我用 jmeter 对此进行了测试测试 1000 个请求去访问每个任务线程休眠时间设的为 1 秒TPS 为 20 多。一想这确实挺低的然后分析其原因想着是不是 springBoot 的线程数给的太少了于是乎又把 tomcat 的最大线程数进行了修改由默认的 200 修改为了 500但发现没啥大的变化想了想后可能问题不是 tomcat 的配置导致的。server: tomcat: max-threads: 500 然后又通过 Java VisualVM 工具看了看线程信息没发现啥问题。然后出去静了静听了一两首音乐后想着起来 Executors 还有一个 newCachedThreadPool() 的用法它与 newFixedThreadPool() 的区别通过源码可以大概知道个一二newFixedThreadPool /** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue. At any point, at most * {code nThreads} threads will be active processing tasks. * If additional tasks are submitted when all threads are active, * they will wait in the queue until a thread is available. * If any thread terminates due to a failure during execution * prior to shutdown, a new one will take its place if needed to * execute subsequent tasks. The threads in the pool will exist * until it is explicitly {link ExecutorService#shutdown shutdown}. * * param nThreads the number of threads in the pool * return the newly created thread pool * throws IllegalArgumentException if {code nThreads 0} */ public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }newCachedThreadPool: /** * Creates a thread pool that creates new threads as needed, but * will reuse previously constructed threads when they are * available. These pools will typically improve the performance * of programs that execute many short-lived asynchronous tasks. * Calls to {code execute} will reuse previously constructed * threads if available. If no existing thread is available, a new * thread will be created and added to the pool. Threads that have * not been used for sixty seconds are terminated and removed from * the cache. Thus, a pool that remains idle for long enough will * not consume any resources. Note that pools with similar * properties but different details (for example, timeout parameters) * may be created using {link ThreadPoolExecutor} constructors. * * return the newly created thread pool */ public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }newFixedThreadPool 是创建一个大小固定的线程池线程数固定也不会被回收newCachedThreadPool 是创建一个大小为 MAX_VALUE 的线程数并具有缓存功能如果 60 秒内线程一直 处于空闲则会进行回收另外线程池的 shutdown 方法 doc 文档的解释如下“Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down. This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.”指的是等待线程池执行 shutdown 方法后就不再接收新的执行目标了等当前线程池中的现场执行完毕后此线程池就会关闭掉了。通过查看 JAVA 源码中的注释信息后才得知原来我之前写的代码有了一个大大的 BUG不应该执行完一次后就立即把线程池给 shutdown 掉这样的话线程池的意义就没多大的意思了跟 new Thread 的就差不多了。尴尬了然后将测试代码修改为如下的代码import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;import java.util.concurrent.atomic.AtomicInteger; RestControllerRequestMapping(value test)public class TestController { private Logger logger LoggerFactory.getLogger(this.getClass()); private AtomicInteger atomicInteger new AtomicInteger(0); final ExecutorService executorService Executors.newCachedThreadPool(); RequestMapping(value doTest) public Object doTest(RequestParam(defaultValue false) Boolean shutdown, RequestParam(defaultValue 10) Integer threadCount, RequestParam(defaultValue 100) Integer sleepTime, RequestParam(defaultValue 10) Integer queryCount) { long beginTime System.currentTimeMillis();// final ExecutorService executorService Executors.newFixedThreadPool(threadCount); for (int i 0; i int finalI i; Callable callable new Callable() { Override public Integer call() throws Exception { Thread.sleep(sleepTime); logger.debug(index:{} threadInfo:{}, finalI, Thread.currentThread().toString());return finalI; } }; FutureTask futureTask new FutureTask(callable); executorService.submit(futureTask); }if (shutdown) { executorService.shutdown(); } Long endTime System.currentTimeMillis(); endTime endTime - beginTime; logger.info(info:{}, endTime);return atomicInteger.addAndGet(endTime.intValue()) this: endTime; }}调用时shutdown 传入 false并且线程池的 new 方法放到上面的公共方法区域中而不应该是来一个请求就 new 一个线程池出来。然后将同样的请求用 jmeter 测试后发现能达到 300 多了比之前的 20 多提升了许多倍总结通过上面的测试发现了一个我之前用错的 JAVA 线程池的用法通过 jmeter 工具测试后才知道其性能是如何的大。同时在通过修改 springboot 的配置信息后发现 springBoot 能创建的线程池最大线程数也与其 tomcat 的最大线程数有关具体身体关系还得靠后面的慢慢探索了。(贼尴尬这么基础的代码问题居然给犯下了这么大一个错误. 还好及时地修改了。哈哈)作者水中加点糖来源链接https://blog.csdn.net/puhaiyang/article/details/80530495