können die Wiederverwendung von Threads realisieren und das erneute Erstellen und Zerstören von Threads vermeiden. Das Erstellen und Zerstören von Threads ist für die CPU sehr kostspielig.
Sie können die maximale Anzahl der Threads begrenzen, die erstellt werden können, und die Thread-Pool-Parameter dynamisch an die Leistung Ihres eigenen Computers anpassen, um die Anwendungsleistung zu verbessern.
Bietet Funktionen wie geplante Ausführung und Parallelitätskontrolle.
Einheitliche Verwaltung von Threads.
1: Cache-Thread-Pool (nicht empfohlen)
2: Thread-Pool mit fester Kapazität (nicht empfohlen)
3: Einzelner Thread-Pool (nicht empfohlen)
4: Timing Aufgaben-Thread-Pool (nicht empfohlen)
5: Erstellen Sie einen Thread-Pool über die ThreadPoolExecutor-Konstruktionsmethode (im Alibaba-Entwicklungshandbuch dringend empfohlen)
Die ersten vier Möglichkeiten zum Erstellen eines Thread-Pools werden alle über die statischen Methoden von Executors erstellt.
ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
Warum wird der zwischengespeicherte Thread-Pool nicht empfohlen?
Quellcode-Analyse
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
Anhand der beiden oben genannten Codeausschnitte können wir sehen, dass die maximale PoolSize von CachedThreadPool der Maximalwert von Integer 2147483647 ist, was einer unbegrenzten Thread-Erstellung entspricht, und das Erstellen von Threads erfordert Speicher, was zu einem Speicherüberlauf führt , und normale Maschinen benötigen keinen so großen Speicher, um eine so große Anzahl von Threads zu erstellen.
newFixedThreadPool(int num), num ist die feste Anzahl von Threads, die wir angeben möchten
ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
Ausgabe:
pool-1-thread-5
run>4
pool- 1-thread-4run>3
pool-1-thread-5run>5
pool-1-thread-3run>2
pool- 1- thread-3run>8
pool-1-thread-3run>9
pool-1-thread-2run>1
pool-1- thread- 1run>0
pool-1-thread-5run>7
pool-1-thread-4run>6
Es ist zu sehen dass Threads zur Wiederverwendung verwendet werden.
Warum ist FixedThreadPool ein fester Thread-Pool?
Quellcode-Analyse
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
Aus diesem Quellcode ist ersichtlich, dass die Anzahl der Kern-Threads (corePoolSize) und die maximale Anzahl von Threads (maximumPoolSize) beide nThreads sind, da der Thread-Pool nur auf diese Weise nicht vorhanden ist erweitert und die Anzahl der Threads wird festgelegt.
ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
Warum enthält SingleThreadExecutor nur einen Thread?
Quellcode-Analyse
public static ExecutorService newSingleThreadExecutor() { return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }
Aus diesem Quellcode ist ersichtlich, dass die Anzahl der Kernthreads (corePoolSize) und die maximale Anzahl von Threads (maximumPoolSize) jeweils 1 sind, sodass nur ein Thread enthalten ist.
int initDelay=10; //初始化延时 int period=1;//初始化延迟过了之后,每秒的延时 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"); } },initDelay,period, TimeUnit.SECONDS);
Die Wirkung dieses Codes ist: Warten Sie 10 Sekunden, nachdem das Programm ausgeführt wurde, geben Sie dann das erste Ergebnis aus und geben Sie das Ergebnis dann alle 1 Sekunde aus.
Warum wird ScheduledThreadPool nicht empfohlen?
Quellcode-Analyse
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue()); }
Es ist ersichtlich, dass die maximale Anzahl von Threads (maximumPoolSize) von ScheduledThreadPool dem Maximalwert von Integer 2147483647 entspricht, was einer unbegrenzten Thread-Erstellung entspricht, und das Erstellen von Threads erfordert Speicher, was zu einem Speicherüberlauf führt , und im Allgemeinen Die Maschine verwendet keinen so großen Speicher, um eine so große Anzahl von Threads zu erstellen.
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 12; i++) { final int finalI = i; threadPoolExecutor.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { }
corePoolSize: die Anzahl der Kern-Threads. Sobald diese Threads erstellt wurden, werden sie nicht zerstört und bleiben immer bestehen. Der Thread-Pool verfügt standardmäßig über keine Threads. Wenn eine Aufgabe eintrifft, wird über ThreadFactory ein Thread erstellt, der immer vorhanden ist.
maximumPoolSize: Maximale Anzahl von Threads. Die Anzahl der Nicht-Kern-Threads = MaximumPoolSize-CorePoolSize. Die Anzahl der Nicht-Kern-Threads entspricht tatsächlich der Anzahl der skalierbaren Threads und kann zerstört werden.
keepAliveTime: Die Leerlaufzeit von Nicht-Kern-Threads. Wenn die Anzahl der durch die Erweiterung generierten Nicht-Kern-Threads nach der keepAliveTime immer noch im Leerlauf ist, werden diese Nicht-Kern-Threads zerstört.
Einheit: Zeiteinheit von keepAliveTime, zum Beispiel: Sekunden
workQueue: Wartebereich. Wenn eine Aufgabe > corePoolSize eintrifft, wird die Aufgabe in der blockierenden Warteschlange von workQueue gespeichert und wartet darauf, dass andere Threads sie verarbeiten.
threadFactory: Thread-Fabrik. Eine Möglichkeit, Threads zu erstellen.
Handler: Ablehnungsstrategie. Wenn es um > die maximale Anzahl von Threads + die Kapazität von workQueue geht, wird die Ablehnungsrichtlinie ausgeführt
ArrayBlockingQueue: begrenzte Blockierungswarteschlange. Die Warteschlange hat eine Größenbeschränkung. Wenn die Kapazität überschritten wird, wird die Erweiterungs- oder Ablehnungsrichtlinie ausgelöst.
public ArrayBlockingQueue(int capacity) { this(capacity, false); }
LinkedBlockingQueue: Unbegrenzte Blockierungswarteschlange, die Warteschlange hat keine Größenbeschränkung und kann zu einem Speicherüberlauf führen.
public LinkedBlockingQueue() { this(2147483647); }
AbortPolicy: Eine Ausnahme direkt auslösen
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
DiscardPolicy: Es wird keine Operation ausgeführt. Verwerfen Sie die Aufgabe stillschweigend.
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }
DiscardOldestPolicy: Verwerfen Sie die am längsten vorhandene Aufgabe
ThreadFactory threadFactory = Executors.defaultThreadFactory(); threadFactory.newThread(new Runnable() { @Override public void run() { System.out.println("threadFactory"); } }).start();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 26; i++) { //并发数26 final int finalI = i; threadPoolExecutor.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); } /** * 核心线程数=10,最大线程数=20,故可扩容线程数=20-10 * BlockingQueue的大小为5,故等待区的大小为5,也就是当并发数<=核心线程数+5不会扩容,并发数大于16才会扩容 * * 触发扩容:并发数>核心线程数+阻塞队列的大小 * 对于这段代码,如果来了26个并发,10个并发会被核心线程处理,5个会在等待区,剩下11个会因为等待区满了而触发扩容 * 因为这里最多能够扩容10个,这里却是11个,所以会触发拒绝策略 */
为什么这段代码会触发拒绝策略
对于这段代码,如果来了26个并发,10个并发会被核心线程处理,5个会在等待区,剩下11个会因为等待区满了而触发扩容,但是又因为因为这里最多能够扩容10个,这里却是11个,所以会触发拒绝策略。
怎么触发扩容
触发扩容:并发数>核心线程数(corePoolSize)+阻塞队列(workQueue)的大小
使用Java纯手写一个线程池
Das obige ist der detaillierte Inhalt vonSo erstellen Sie einen Java-Thread-Pool. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!