线程和线程池原理及demo演示
线程和线程池原理及demo演示
创建一个线程有两种方式:
1.继承Thread类
2.实现Runnable接口
但也带来了下面的问题:
创建和销毁一个线程,都是比较耗时,频繁的创建和销毁线程,非常影响系统的性能。
无限制的创建线程,会导致内存不足。
有新任务过来时,必须要先创建好线程才能执行,不能直接复用线程。
为了解决上面的这些问题,Java中引入了:线程池。
它相当于一个存放线程的池子。
使用线程池带来了下面3个好处:
1.降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2.提高响应速度。当任务到达时,可以直接使用已有空闲的线程,不需要的等到线程创建就能立即执行。
3.提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。而如果我们使用线程池,可以对线程进行统一的分配、管理和监控。
线程池的构造器:
public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
参数说明:
corePoolSize:核心线程数,线程池维护的最少线程数。
maximumPoolSize:最大线程数,线程池允许创建的最大线程数。
keepAliveTime:线程存活时间,当线程数超过核心线程数时,多余的空闲线程的存活时间。
unit:时间单位。
workQueue:任务队列,用于保存等待执行的任务。
threadFactory:线程工厂,用于创建新线程。
handler:拒绝策略,当任务无法执行时的处理策略。
线程池的工作过程如下:
1.线程池初始化:根据corePoolSize初始化核心线程。
2.任务提交:当任务提交到线程池时,根据当前线程数判断:
3.若当前线程数小于corePoolSize,创建新的线程执行任务。
4.若当前线程数大于或等于corePoolSize,任务被加入workQueue队列。
5.任务处理:当有空闲线程时,从workQueue中取出任务执行。
6.线程扩展:若队列已满且当前线程数小于maximumPoolSize,创建新的线程处理任务。
7.线程回收:当线程空闲时间超过keepAliveTime,多余的线程会被回收,直到线程数不超过corePoolSize。
8.拒绝策略:若队列已满且当前线程数达到maximumPoolSize,则根据拒绝策略处理新任务。
package com.example.core.mydemo.thread; import java.util.concurrent.*; public class ExecutorServiceTest { public static void main(String[] args) { /** * 设置10个线程 * 队列过大 * 如果向newFixedThreadPool线程池中提交的任务太多,可能会导致LinkedBlockingQueue非常大,从而出现OOM问题。 */ ExecutorService executorService = Executors.newFixedThreadPool(10); /** * */ ExecutorService executorService2 = Executors.newSingleThreadExecutor(); /** * 线程太多 * 如果向newCachedThreadPool线程池中提交的任务太多,可能会导致创建大量的线程,也会出现OOM问题。 */ ExecutorService executorService3 = Executors.newCachedThreadPool(); //自定义线程 ThreadPoolExecutor /** * 上面的OOM问题,我们在日常开发中,可以通过自定义线程池的方式解决。 * 自定义了一个最大线程数量和任务队列都在可控范围内线程池。 */ ThreadPoolExecutor executorService4 = new ThreadPoolExecutor(8, 10, 30L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300)); ScheduledExecutorService scheduledExecutorService5 = Executors.newScheduledThreadPool(2); /** * 线程运行 * Thread Name: pool-1-thread-1time:2024-09-18T18:10:01.417 */ executorService.submit(new MyRunnable()); /** * 线程运行 * Thread Name: pool-2-thread-1time:2024-09-18T18:09:29.972 */ // executorService2.submit(new MyRunnable()); /** * Thread Name: pool-3-thread-1time:2024-09-18T18:08:55.597 */ // executorService3.submit(new MyRunnable()); // /** * 线程运行 * Thread Name: pool-4-thread-1time:2024-09-18T18:08:30.520 */ // executorService4.submit(new MyRunnable()); // /** * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T18:08:03.031 */ // scheduledExecutorService5.submit(new MyRunnable()); /** * 单词执行:线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T18:07:14.710 */ // scheduledExecutorService5.execute(new MyRunnable()); /** * link: 使用ScheduledExecutorService代替下Timer * https://www.cnblogs.com/oktokeep/p/17000649.html */ /** * output: 执行5s,等待4s,所以间隔是9s * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T17:58:33.861 * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T17:58:42.862 * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T17:58:51.864 */ // scheduledExecutorService5.scheduleWithFixedDelay(new MyRunnable(),1,4, TimeUnit.SECONDS); /** * output:执行5s,等待0s(立即执行),所以间隔是5s * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T17:59:44.928 * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T17:59:49.928 * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T17:59:54.929 */ /** * output:执行3s,等待:(4-3=1s),所以间隔是4s * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T18:00:43.648 * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T18:00:47.612 * 线程运行 * Thread Name: pool-5-thread-1time:2024-09-18T18:00:51.612 */ // scheduledExecutorService5.scheduleAtFixedRate(new MyRunnable(),1,4, TimeUnit.SECONDS); } } package com.example.core.mydemo.thread; import java.time.LocalDateTime; /** * class Thread implements Runnable { * main Thread Name: main * 线程运行 * Thread Name: Thread-0time:2024-11-19T15:38:07.668 */ public class MyRunnable implements Runnable{ @Override public void run() { System.out.println("线程运行"); Thread currentThread = Thread.currentThread(); System.out.println("Thread Name: " + currentThread.getName() + "time:" + LocalDateTime.now()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { MyRunnable myThread = new MyRunnable(); // myThread.run(); //这样调用不是使用新的线程。打印出来仍然是主线程。 //通过thread触发 Thread thread = new Thread(myThread); thread.start(); Thread currentThread = Thread.currentThread(); System.out.println("main Thread Name: " + currentThread.getName()); } } package com.example.core.mydemo.thread; /** * class Thread implements Runnable { * main线程名称=main * 线程运行Thread-0 */ public class MyThread extends Thread{ @Override public void run() { System.out.println("线程运行" + currentThread().getName()); } public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); System.out.println("main线程名称="+ currentThread().getName()); } }