Heim  >  Artikel  >  Java  >  Wie Spring Boot den Thread-Pool verwendet, um Zehntausende Dateneinfügungsfunktionen zu verarbeiten

Wie Spring Boot den Thread-Pool verwendet, um Zehntausende Dateneinfügungsfunktionen zu verarbeiten

WBOY
WBOYnach vorne
2023-05-12 22:22:041207Durchsuche

# Vorwort

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

# Verwendungsschritte

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 muss

Hier 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: beendeexecuteAsync
2022-07-16 22:15:47.770 INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl: starteexecuteAsync

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();
}
Wie 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()

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]
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

Achten Sie auf diese Zeile von log:

# 🎜🎜#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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen