Java-Multithreading ruft Webseitendaten ab und aktualisiert die Datenbank

Erstellen Sie zunächst den Thread-Pool MyThreadPool:

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/*
* 多线程线程池配置
*/
public class MyThreadPool {
    
    

    public static ThreadPoolExecutor threadExecutor = new ThreadPoolExecutor(
            10,   //核心线程数
            Runtime.getRuntime().availableProcessors(),
            100,  //线程空闲时的存活时间
            TimeUnit.SECONDS,  //时间单位设置-秒
            new LinkedBlockingDeque(1024), //线程阻塞队列
            Executors.defaultThreadFactory(),  //创建线程的工厂
            new ThreadPoolExecutor.CallerRunsPolicy() //线程池的饱和策略
    );
}

Erklären Sie diese Parameter:
1.
Die Anzahl der Kernthreads im corePoolSize-Thread-Pool. Wenn eine Aufgabe übermittelt wird, erstellt der Thread-Pool einen neuen Thread, um die Aufgabe auszuführen, bis die aktuelle Anzahl der Threads gleich corePoolSize ist; wenn die aktuelle Anzahl
von threads ist corePoolSize, weiterleiten. Aufgaben werden in einer blockierenden Warteschlange gespeichert und warten auf ihre Ausführung.
2. MaximumPoolSize
Die maximal zulässige Anzahl von Threads im Thread-Pool. Wenn die aktuelle Blockierungswarteschlange voll ist und die Aufgabe weiterhin übermittelt wird, wird ein neuer Thread zum Ausführen der Aufgabe erstellt. Vorausgesetzt, die aktuelle Anzahl der Threads ist kleiner als die maximale PoolSize, besteht die hier verwendete Funktion darin, verfügbare Rechenressourcen abzurufen 3. keepAliveTime Die Überlebenszeit, wenn der Thread im Leerlauf ist, d. Runtime.getRuntime().availableProcessors(),h
.
wenn der Thread keine Aufgaben auszuführen hat, die Zeit, in der er weiterlebt. Standardmäßig ist dieser Parameter nur nützlich, wenn die Anzahl der Threads größer als corePoolSize
4 ist. TimeUnit
keepAliveTime-Zeiteinheit, optionale Tage, Stunden, Minuten, Sekunden, Millisekunden usw.
5. workQueue
workQueue muss eine BlockingQueue-Blockierungswarteschlange sein. Wenn die Anzahl der Threads im Thread-Pool seine corePoolSize überschreitet, tritt der Thread in die Blockierungswarteschlange ein, um zu warten. Über workQueue realisiert der Thread-Pool die Blockierungsfunktion

Warteschlangenklasse Struktur
ArrayBlockingQueue Die Array-Struktur bildet eine begrenzte Blockierungswarteschlange, das First-In-First-Out-Prinzip, die Initialisierung muss die Größe übergeben, und für Take und Put wird dieselbe Sperre verwendet
LinkedBlockingQueue Begrenzte Blockierungswarteschlange, bestehend aus einer verknüpften Listenstruktur, dem First-In-First-Out-Prinzip, der Initialisierung kann die Größe nicht übergeben werden, die Sperre wird gesetzt und übernommen
PriorityBlockingQueue Unbegrenzte Blockierungswarteschlange, die Prioritätssortierung, Sortierung, aufsteigende Reihenfolge in natürlicher Reihenfolge und Änderungsreihenfolge unterstützt: Die Klasse implementiert die Methode „compareTo()“ selbst, initialisiert PriorityBlockingQueue und gibt einen Komparator an
Verzögerungswarteschlange Eine unbegrenzte Blockierungswarteschlange, die eine Prioritätswarteschlange verwendet, unterstützt die verzögerte Erfassung, und die Elemente in der Warteschlange müssen die Verzögerungsschnittstelle implementieren. DelayQueue ist sehr nützlich und kann in den folgenden Anwendungsszenarien verwendet werden. Das Design des Cache-Systems: DelayQueue kann verwendet werden, um die Gültigkeitsdauer der zwischengespeicherten Elemente zu speichern, und ein Thread kann verwendet werden, um DelayQueue in einer Schleife abzufragen. Sobald die Elemente aus DelayQueue abgerufen werden können, bedeutet dies, dass der Cache Gültigkeitsdauer ist erreicht. Es gibt auch Bestellabläufe, zeitlich begrenzte Zahlungen und mehr.
SynchronousQueue Eine blockierende Warteschlange, die keine Elemente speichert. Jede Put-Operation muss auf eine Take-Operation warten
LinkedTransferQueue Eine unbegrenzte Blockierungswarteschlange, bestehend aus einer verknüpften Listenstruktur, Transfer, tryTransfer, wenn der Produzent es einfügt, gibt es derzeit eine Verbraucheraufnahme, und der Produzent übergibt das Element direkt an den Verbraucher
LinkedBlockingDeque Die aus einer verknüpften Listenstruktur bestehende bidirektionale Blockierungswarteschlange kann an beiden Enden der Warteschlange eingefügt und entfernt werden: xxxFirst-Kopfoperation, xxxLast-Endoperation. Arbeitsdiebstahlmuster

Letzteres wird hier verwendet und die Größe der Blockierungswarteschlange kann etwas größer angepasst werden

6.ThreadFactory
erstellt eine Thread-Factory. Über die benutzerdefinierte Thread-Factory können Sie für jeden neu erstellten Thread einen erkennbaren Thread-Namen festlegen. Die Standard-ThreadFactory in der statischen Executors-Factory lautet die Thread-Benennungsregel „Pool-Nummer-Thread-Nummer“. , hier verwenden Sie die Standardeinstellung

7.
Die Sättigungsstrategie des RejectedExecutionHandler-Thread-Pools. Wenn die Blockierungswarteschlange voll ist und keine inaktiven Arbeitsthreads vorhanden sind und die Aufgabe weiterhin übermittelt wird, muss eine Strategie zur Verarbeitung der Aufgabe übernommen werden. Der Thread-Pool bietet 4 Strategien:

(1) AbortPolicy: Eine Ausnahme direkt auslösen, die Standardrichtlinie;
(2) CallerRunsPolicy: Verwenden Sie den Thread, in dem sich der Aufrufer befindet, um die Aufgabe auszuführen; (
3) DiscardOldestPolicy: Verwerfen Sie die vorderste Aufgabe in der Blockierungswarteschlange und führen Sie die aktuelle Aufgabe aus ;
(4) DiscardPolicy: Aufgabe direkt verwerfen;
hier ist zu beachten, dass das Standardbeispiel im Internet im Allgemeinen das erste verwendet. Wenn ich es hier verwende, löst es aufgrund der unangemessenen Parametereinstellung direkt eine Ausnahme aus und beendet die Programm. Hier habe ich Ja, das zweite wird verwendet.

Die im Unternehmen verwendete Logik ist wie folgt:

public void updateByBatch(List<VervelClient> clients) {
    
    
        int tatol = clients.size();
        //开启多线程处理
        CountDownLatch countDownLatch = new CountDownLatch(tatol);
        clients.forEach(vervelClient -> {
    
    
            MyThreadPool.threadExecutor.execute(()->{
    
    
                updateSelectiveById(vervelClient);
                countDownLatch.countDown();
            });
        });
        try {
    
    
            countDownLatch.await();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }

countDown()
verringert den aktuellen Zählerwert um eins, wenn dieser größer als Null ist, und gibt alle wartenden Threads frei, wenn der neue Zählerwert gleich Null ist.
Sobald der Zähler Null erreicht, wird er nicht mehr dekrementiert.
Wenn der aktuelle Zähler Null ist, unternehmen Sie nichts.
Diese Methode blockiert nicht.
wait()
bewirkt, dass der aktuelle Thread wartet, bis der Wert des Zählers Null wird, es sei denn, der Thread wird unterbrochen. Wenn der Zähler bereits Null ist, kehren Sie sofort zurück.

Ohne die Verwendung von Multithreading ist es sehr langsam, die Datenbank immer wieder zu aktualisieren. Durch die Verwendung von Multithreading wird die Geschwindigkeit erheblich verbessert

Referenzlink: Zeichnen Sie eine Multithread-Verarbeitung einer großen MySQL-Batch-Datenaktualisierung auf

Detaillierte Konfiguration von ThreadPoolExecutor

[Java] Wie kann ich die drei Kernattribute von ThreadPoolExecutor verstehen und festlegen? Unter welchen Umständen übersteigt die Anzahl der Arbeitsthreads die Anzahl der Kernthreads? Welche Strategien zur Aufgabenablehnung gibt es?

Guess you like

Origin blog.csdn.net/weixin_42260782/article/details/131081437