How to develop a custom thread pool in Java
The start and end of each thread are time consuming and resource consuming.
If a lot of threads are used in the system, a lot of start and end actions will cause the performance of the system to become stuck and the response to slow down.
In order to solve this problem, the design idea of thread pool is introduced.
The mode of thread pool is very similar to that of producer and consumer. The object of consumption is a task that can run
Step 1: thread pool design
The thread pool idea is very close to the producer consumer model.
- Prepare a task container
- Start 10 consumer threads at once
- At the beginning, the task container is empty, so all threads wait on it.
- Until an external thread throws a "task" into the task container, a consumer thread will be awakened to notify
- The consumer thread takes out the "task" and executes the task. After execution, it continues to wait for the next task.
- If more tasks are added in a short time, multiple threads will be awakened to perform these tasks.
In the whole process, it is not necessary to create new threads, but to recycle these existing threads
Step 2: develop a custom thread pool
This is a custom thread pool. Although it is not perfect and robust, it is enough to explain the working principle of thread pool
Slowly add tasks to this thread pool, and you will see that there are multiple threads to perform these tasks.
After thread 7 finishes executing the task, it returns to the pool. When the next task comes, thread 7 will execute the new task again.
package multiplethread; import java.util.LinkedList; public class ThreadPool { // Thread pool size int threadPoolSize; // Task container LinkedList<Runnable> tasks = new LinkedList<Runnable>(); // Thread attempting to consume task public ThreadPool() { threadPoolSize = 10; // Start 10 task consumer threads synchronized (tasks) { for (int i = 0; i < threadPoolSize; i++) { new TaskConsumeThread("Task consumer thread " + i).start(); } } } public void add(Runnable r) { synchronized (tasks) { tasks.add(r); // Wake up waiting task consumer thread tasks.notifyAll(); } } class TaskConsumeThread extends Thread { public TaskConsumeThread(String name) { super(name); } Runnable task; public void run() { System.out.println("Start up: " + this.getName()); while (true) { synchronized (tasks) { while (tasks.isEmpty()) { try { tasks.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } task = tasks.removeLast(); // Threads allowed to add tasks can continue to add tasks tasks.notifyAll(); } System.out.println(this.getName() + " Get the task and execute"); task.run(); } } } }
.
package multiplethread; public class TestThread { public static void main(String[] args) { ThreadPool pool = new ThreadPool(); for (int i = 0; i < 5; i++) { Runnable task = new Runnable() { @Override public void run() { //System.out.println("perform task"); //The task might be to print a sentence //May be accessing files //Maybe it's sorting } }; pool.add(task); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
Step 3: test the thread pool
Create a scenario where each task takes one second to execute
At first, add tasks to the thread pool every 1 second
Then the interval is getting shorter and shorter, the thread executing the task has not finished yet, and the new task is coming again.
You'll see other threads in the thread pool wake up to perform these tasks
package multiplethread; public class TestThread { public static void main(String[] args) { ThreadPool pool= new ThreadPool(); int sleep=1000; while(true){ pool.add(new Runnable(){ @Override public void run() { //System.out.println("perform task"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); try { Thread.sleep(sleep); sleep = sleep>100?sleep-100:sleep; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
Step 4: use java's own thread pool
java provides its own thread pool instead of developing a custom thread pool.
Thread pool class ThreadPoolExecutor is under package java.util.concurrent
ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
The first parameter 10 indicates that this thread pool has initialized 10 threads to work in
The second parameter 15 indicates that if 10 threads are not enough, it will be increased to 15 threads at most
The third parameter 60, combined with the fourth parameter TimeUnit.SECONDS, indicates that after 60 seconds, the extra threads will be recycled before they receive the work, and finally 10 threads will be kept in the pool
The fourth parameter, TimeUnit.SECONDS, is as above
The fifth parameter, new LinkedBlockingQueue(), is used to put the collection of tasks
The execute method is used to add new tasks
package multiplethread; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class TestThread { public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); threadPool.execute(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub System.out.println("Task 1"); } }); } }
Practice: Find file content synchronously with thread pool
In practice - find the contents of files synchronously, if there are too many files, many threads will be created. Rewrite this exercise using the thread pool approach.
Initializing a thread pool of size 10
Traverse all files. When the file is. java, create a task to find the file, throw the task into the thread pool to execute, and continue to traverse the next file
Answer:
SearchFileTask.java
package multiplethread; import java.io.File; import java.io.FileReader; import java.io.IOException; public class SearchFileTask implements Runnable{ private File file; private String search; public SearchFileTask(File file,String search) { this.file = file; this.search= search; } public void run(){ String fileContent = readFileConent(file); if(fileContent.contains(search)){ System.out.printf( "thread: %s Sub target string found%s,In document:%s%n",Thread.currentThread().getName(), search,file); } } public String readFileConent(File file){ try (FileReader fr = new FileReader(file)) { char[] all = new char[(int) file.length()]; fr.read(all); return new String(all); } catch (IOException e) { e.printStackTrace(); return null; } } }
ThreadPool.java
package multiplethread; import java.util.LinkedList; public class ThreadPool { // Thread pool size int threadPoolSize; // Task container LinkedList<Runnable> tasks = new LinkedList<Runnable>(); // Thread attempting to consume task public ThreadPool() { threadPoolSize = 10; // Start 10 task consumer threads synchronized (tasks) { for (int i = 0; i < threadPoolSize; i++) { new TaskConsumeThread("Task consumer thread " + i).start(); } } } public void add(Runnable r) { synchronized (tasks) { tasks.add(r); // Wake up waiting task consumer thread tasks.notifyAll(); } } class TaskConsumeThread extends Thread { public TaskConsumeThread(String name) { super(name); } Runnable task; public void run() { while (true) { synchronized (tasks) { while (tasks.isEmpty()) { try { tasks.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } task = tasks.removeLast(); // Threads allowed to add tasks can continue to add tasks tasks.notifyAll(); } task.run(); } } } }
TestThread.java
package multiplethread; import java.io.File; public class TestThread { static ThreadPool pool= new ThreadPool(); public static void search(File file, String search) { if (file.isFile()) { if(file.getName().toLowerCase().endsWith(".java")){ SearchFileTask task = new SearchFileTask(file, search); pool.add(task); } } if (file.isDirectory()) { File[] fs = file.listFiles(); for (File f : fs) { search(f, search); } } } public static void main(String[] args) { File folder =new File("e:\\project"); search(folder,"Magic"); } }