Heim >Java >javaLernprogramm >Wie Spring Boot den Thread-Pool verwendet, um Zehntausende Dateneinfügungsfunktionen zu verarbeiten
Als ich vor zwei Tagen an einem Projekt arbeitete, wollte ich die Leistungsoptimierung beim Einfügen von Tabellen verbessern. Da es zwei Tabellen gibt, wäre das Einfügen der alten Tabelle und dann der neuen Tabelle für mehr etwas langsam
Ich habe später an den Thread-Pool ThreadPoolExecutor gedacht, und mit dem Spring Boot-Projekt können Sie den von Spring bereitgestellten Thread-Pool ThreadPoolTaskExecutor verwenden, um den ThreadPoolExecutor zu kapseln und ihn direkt mit Anmerkungen zu aktivieren
Erstellen Sie zunächst eine Thread-Pool-Konfiguration und lassen Sie sie von Spring Boot laden, um zu definieren, wie ein ThreadPoolTaskExecutor erstellt wird. Verwenden Sie die beiden Annotationen @Configuration und @EnableAsync, um anzugeben, dass es sich um eine Konfigurationsklasse und die Konfigurationsklasse handelt Thread-Pool
@Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Value("${async.executor.thread.core_pool_size}") private int corePoolSize; @Value("${async.executor.thread.max_pool_size}") private int maxPoolSize; @Value("${async.executor.thread.queue_capacity}") private int queueCapacity; @Value("${async.executor.thread.name.prefix}") private String namePrefix; @Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //配置核心线程数 executor.setCorePoolSize(corePoolSize); //配置最大线程数 executor.setMaxPoolSize(maxPoolSize); //配置队列大小 executor.setQueueCapacity(queueCapacity); //配置线程池中的线程的名称前缀 executor.setThreadNamePrefix(namePrefix); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //执行初始化 executor.initialize(); return executor; } }
@Value ist das, was ich in den Anwendungseigenschaften konfiguriert habe. Sie können sich auf die Konfiguration beziehen und frei definieren
# 异步线程配置 # 配置核心线程数 async.executor.thread.core_pool_size = 5 # 配置最大线程数 async.executor.thread.max_pool_size = 5 # 配置队列大小 async.executor.thread.queue_capacity = 99999 # 配置线程池中的线程的名称前缀 async.executor.thread.name.prefix = async-service-
Erstellen Sie eine Service-Schnittstelle, bei der es sich um die Schnittstelle für asynchrone Threads handelt
public interface AsyncService { /** * 执行异步任务 * 可以根据需求,自己加参数拟定,我这里就做个测试演示 */ void executeAsync(); }
Implementierungsklasse
@Service public class AsyncServiceImpl implements AsyncService { private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class); @Override @Async("asyncServiceExecutor") public void executeAsync() { logger.info("start executeAsync"); System.out.println("异步线程要做的事情"); System.out.println("可以在这里执行批量插入等耗时的事情"); logger.info("end executeAsync"); } }
Hinzufügen Die Annotation @Async("asyncServiceExecutor") zur MethodeexecuteAsync() ist der vordere Methodenname in ExecutorConfig.java, der angibt, dass der von der MethodeexecuteAsync eingegebene Threadpool von der MethodeasyncServiceExecutorerstellt wird
Der nächste Schritt besteht darin, den Dienst über die Annotation @Autowired im Controller oder irgendwo einzuschleusen. AsyncServiceImpl: ExecuteAsync starten
Was der asynchrone Thread tun mussHier können Sie zeitaufwändige Dinge wie Batch-Einfügungen durchführen
2022-07 -16 22:15:47.655 INFO 10516 --- [async-service-5] c.u.d.e.executor .impl.AsyncServiceImpl: beendeexecuteAsync2022-07-16 22:15:47.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl: starteexecuteAsyncWie oben gezeigt, werden in der showThreadPoolInfo-Methode die Gesamtzahl der Aufgaben, die Anzahl der abgeschlossenen Aufgaben, Die Anzahl der aktiven Threads und die Warteschlangengröße werden ausgedruckt, und dann werden die Methoden „execute“, „submit“ und andere der übergeordneten Klasse überschrieben und die Methode „showThreadPoolInfo“ aufgerufen, sodass jedes Mal eine Aufgabe an den Thread gesendet wird Im Pool wird die Grundsituation des aktuellen Thread-Pools im Protokoll ausgegeben. Ändern Sie die asyncServiceExecutor-Methode von ExecutorConfig.java und ändern Sie ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() in ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor()Was der asynchrone Thread tun muss
Das kannst du Führen Sie hier zeitaufwändige Dinge wie das Einfügen von Stapeln aus
16.07.2022 22:15:47.770 INFO 10516 --- [async-service- 1] c.u.d.e.executor.impl.AsyncServiceImpl : endexecuteAsync
16.07.2022 22: 15:47.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl :executeAsync starten
Was der asynchrone Thread tun muss
Zeitaufwändige Aufgaben wie Batch-Einfügung können Sie hier ausführen
2022-07- 16 22:15:47.816 INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : endexecuteAsync
2022-07-16 22:15:48.833 INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl: starteexecuteAsync
Was der asynchrone Thread tun muss
Zeitaufwändige Dinge wie Batch-Einfügungen können Sie hier durchführen
2022-07-16 22:15:48.834 INFO 10516 --- [async-service -3] c.u.d.e.executor.impl.AsyncServiceImpl: beendeexecuteAsync
2022-07-16 22:15:48.986 INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl: starteexecuteAsync
Was der asynchrone Thread hat zu tun
Hier können Sie zeitaufwändige Dinge wie das Einfügen von Stapeln ausführen
2022-07-16 22:15:48.987 INFO 10516 --- [async-service-4 ] c.u.d.e.executor.impl.AsyncServiceImpl : endexecuteAsync
Aus dem obigen Protokoll geht hervor, dass [async-service-] über mehrere Threads verfügt und offensichtlich in dem von uns konfigurierten Thread-Pool ausgeführt wurde. Bei jeder Anforderung werden die Start- und Endprotokolle des Controllers kontinuierlich gedruckt, um anzuzeigen dass auf jede Anfrage schnell reagiert wird und zeitaufwändige Vorgänge den Threads im Thread-Pool zur asynchronen Ausführung überlassen werden
Obwohl wir den Thread-Pool verwendet haben, ist noch unklar, wie die Situation des Thread-Pools zu diesem Zeitpunkt war Zeit. Wie viele Threads wurden ausgeführt und wie viele warteten in der Warteschlange? Hier habe ich eine Unterklasse von ThreadPoolTaskExecutor erstellt, die jedes Mal, wenn ein Thread eingereicht wird, den Betriebsstatus des aktuellen Thread-Pools ausgibt@Autowiredprivate AsyncService asyncService; @GetMapping("/async") public void async(){ asyncService.executeAsync(); }
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.concurrent.ListenableFuture; import java.util.concurrent.Callable;import java.util.concurrent.Future;import java.util.concurrent.ThreadPoolExecutor; /** * @Author: 腾腾 * @Date: 2022/7/16/0016 22:19 */ public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor { private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class); private void showThreadPoolInfo(String prefix) { ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor(); if (null == threadPoolExecutor) { return; } logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]", this.getThreadNamePrefix(), prefix, threadPoolExecutor.getTaskCount(), threadPoolExecutor.getCompletedTaskCount(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size()); } @Override public void execute(Runnable task) { showThreadPoolInfo("1. do execute"); super.execute(task); } @Override public void execute(Runnable task, long startTimeout) { showThreadPoolInfo("2. do execute"); super.execute(task, startTimeout); } @Override public Future<?> submit(Runnable task) { showThreadPoolInfo("1. do submit"); return super.submit(task); } @Override public <T> Future<T> submit(Callable<T> task) { showThreadPoolInfo("2. do submit"); return super.submit(task); } @Override public ListenableFuture<?> submitListenable(Runnable task) { showThreadPoolInfo("1. do submitListenable"); return super.submitListenable(task); } @Override public <T> ListenableFuture<T> submitListenable(Callable<T> task) { showThreadPoolInfo("2. do submitListenable"); return super.submitListenable(task); } }Starten Sie den Projekttest erneut
2022-07-16 22:23:30.951 INFO 14088 --- [nio-8087-exec-2] u.d.e.e.i.VisiableThreadPoolTaskExecutor: async-service-, 2. do subscribe,taskCount [0], completedTaskCount [0], activeCount [0], queueSize [0]
Achten Sie auf diese Zeile von log:
2022-07-16 22:23:30.952 INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : startexecuteAsync# 🎜🎜#Von asynchronen Threads zu erledigende Aufgaben
Hier können Sie zeitaufwändige Aufgaben wie das Einfügen von Stapeln ausführen
2022-07-16 22:23:30.953 INFO 14088 --- [async-service- 1] c.u.d.e.executor.impl.AsyncServiceImpl : endexecuteAsync
2022-07-16 22:23:31.351 INFO 14088 --- [nio-8087-exec-3] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do einreichen, taskCount [1], abgeschlossenTaskCount [1], activeCount [0], queueSize [0]
2022-07-16 22:23:31.353 INFO 14088 --- [async-service-2] c.u.d.e.executor. impl. AsyncServiceImpl: starteexecuteAsync
Was der asynchrone Thread tun muss
Hier können Sie zeitaufwändige Dinge wie Batch-Einfügungen durchführen
2022-07-16 22:23:31.353 INFO 14088 - -- [async -Service-2] C.U.D.E.EXECUTOR.IMPL.ASYNCSERVICEIMPL: END Executeasync
2022-07-16 22: 23: 31.927 Info 14088 --- [NiO-8087-EXEC-5] .siablethreadPooltaskexecutor: Async -Service-, 2. senden,taskCount [2], abgeschlossenTaskCount [2], activeCount [0], queueSize [0]
2022-07-16 22:23:31.929 INFO 14088 --- [async- service-3] c.u.d.e.executor.impl.AsyncServiceImpl : startexecuteAsync
Was der asynchrone Thread tun muss
Hier können Sie zeitaufwändige Dinge wie Batch-Einfügungen durchführen
2022-07-16 22 :23:31.930 INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : endexecuteAsync
2022-07-16 22:23:32.496 INFO 14088 --- [nio-8087-exec -7] u.d.e.e.i.VisiableThreadPoolTaskExecutor: async-service-, 2. senden,taskCount [3], abgeschlossenTaskCount [3], activeCount [0], queueSize [0]
2022-07-16 22:23:32.498 INFO 14088 --- [async -service-4] c.u.d.e.executor.impl.AsyncServiceImpl : startexecuteAsync
Was der asynchrone Thread tun muss
Hier können Sie Batch-Einfügungen und andere zeitaufwändige Dinge durchführen#🎜🎜 #2022-07-16 22: 23:32.499 INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : endexecuteAsync
# 🎜🎜#2022-07-16 22:23:32.496 INFO 14088 --- [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. senden ,taskCount [3], abgeschlossenTaskCount [3], activeCount [0], queueSize [0]
Dies zeigt, dass beim Senden einer Aufgabe an den Thread-Pool die Submit(Aufrufbare Aufgabe) Die Methode wird aufgerufen. Derzeit sind 3 Aufgaben abgeschlossen, 0 Threads verarbeiten derzeit Aufgaben und 0 Aufgaben warten noch in der Warteschlange. Die Grundsituation des Thread-Pools ist vollständig klar.
Das obige ist der detaillierte Inhalt vonWie Spring Boot den Thread-Pool verwendet, um Zehntausende Dateneinfügungsfunktionen zu verarbeiten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!