Home >Java >javaTutorial >java thread pool - asynchronous tasks
1. Simple and crude thread
The most original way, when we want to execute a task in parallel or asynchronously, we will directly use the method of starting a thread, as shown below:
new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub 这里放你要执行的方法 } }).start();
But like the above or There are many disadvantages in this method of using new Thread every time, as follows:
The performance of creating new objects every time new Thread is poor;
Threads lack unified management, and new threads can be created without restrictions, mutually Competition among them may also occupy too many system resources and cause crashes or OOM (Out of Memory);
lacks more functions, such as scheduled execution, periodic execution, thread interruption, etc.
2. Thread Pool
In order to solve these problems, the java.util.concurrent package was added after Jdk1.5. This package mainly introduces the use of threads and thread pools in Java. It provides a lot of help for us to deal with thread issues in development.
1. Function
According to the system environment, the number of threads can be set automatically or manually to achieve the best operation effect; less will waste system resources, and more will cause system congestion and inefficiency. Use the thread pool to control the number of threads, and other threads are queued to wait. After a task is executed, the frontmost task in the queue is taken and execution begins. If there is no waiting process in the queue, this resource of the thread pool is waiting. When a new task needs to be run, if there are waiting worker threads in the thread pool, it can start running; otherwise, it enters the waiting queue.
2. Why use thread pool
Reuse existing threads, reduce the cost of object creation and destruction, and have good performance.
It can effectively control the maximum number of concurrent threads, improve the usage of system resources, and avoid excessive resource competition and congestion.
Provides functions such as scheduled execution, periodic execution, single thread, and concurrency control.
You can adjust the number of working threads in the thread pool according to the system's capacity to prevent the server from being exhausted due to excessive memory consumption (each thread requires about 1MB of memory. The more threads are opened, the more memory is consumed. The memory will be larger and eventually it will crash).
3. Main classes
The top-level interface of the thread pool in Java is Executor, but strictly speaking, Executor is not a thread pool, but just a tool for executing threads. The real thread pool interface is ExecutorService.
It is relatively complicated to configure a thread pool, especially when the principle of the thread pool is not very clear, it is very likely that the configured thread pool is not optimal, so it is provided in the Executors class Create some static factories and generate some commonly used thread pools.
1) newSingleThreadExecutor
Create a single-threaded thread pool. This thread pool has only one thread working, which is equivalent to a single thread executing all tasks serially. If the only thread ends abnormally, a new thread will replace it. This thread pool ensures that all tasks are executed in the order in which they are submitted.
2) newFixedThreadPool
Create a fixed-size thread pool. A thread is created each time a task is submitted, until the thread reaches the maximum size of the thread pool. The size of the thread pool remains unchanged once it reaches the maximum value. If a thread ends due to an execution exception, the thread pool will be replenished with a new thread.
3) newCachedThreadPool
Create a cacheable thread pool. If the size of the thread pool exceeds the threads required to process the task,
then some idle threads (not executing tasks for 60 seconds) will be recycled. When the number of tasks increases, this thread pool can intelligently add new threads to process Task. This thread pool does not limit the size of the thread pool. The size of the thread pool completely depends on the maximum thread size that the operating system (or JVM) can create.
4) newScheduledThreadPool
Create a thread pool of unlimited size. This thread pool supports timing and periodic execution of tasks.
3. Examples
1) newCachedThreadPool
Create a cacheable thread pool. If the length of the thread pool exceeds processing needs, idle threads can be flexibly recycled. If there is no way to recycle, create a new thread. The sample code is as follows:
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExecutorTest { public static void main(String[] args) { ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { public void run() { System.out.println(index); } }); } } }
The thread pool is infinite. When the second task is executed, the first task has been completed, and the thread that executed the first task will be reused instead of creating a new thread each time.
2) newFixedThreadPool
Create a fixed-length thread pool, which can control the maximum number of concurrent threads. Exceeding threads will wait in the queue. The sample code is as follows:
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExecutorTest { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }
Since the thread pool size is 3, each task sleeps for 2 seconds after outputting the index, so 3 numbers are printed every two seconds.
The size of the fixed-length thread pool is best set according to system resources. Such as Runtime.getRuntime().availableProcessors()
3)newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
package test; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorTest { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS); } }
表示延迟3秒执行。
定期执行示例代码如下:
package test; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ThreadPoolExecutorTest { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS); } }
表示延迟1秒后每3秒执行一次。
4)newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExecutorTest { public static void main(String[] args) { ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() { public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }
结果依次输出,相当于顺序执行各个任务。
注意:以上的execute()方法可以替换为submit()方法,执行的结果是一样的。
四、submit()和execute()的区别
JDK5往后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,它们的区别是:
execute(Runnable x) 没有返回值。可以执行任务,但无法判断任务是否成功完成。——实现Runnable接口
submit(Runnable x) 返回一个future。可以用这个future来判断任务是否成功完成。——实现Callable接口