线程和线程池原理及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());
}
}