线程池的介绍和作用

1.什么是线程池

线程池(Thread Pool)是一种并发编程中常用的技术,用于管理和重用线程。它由线程池管理器、工作队列和线程池线程组成。

线程池的基本概念是,在应用程序启动时创建一定数量的线程,并将它们保存在线程池中。当需要执行任务时,从线程池中获取一个空闲的线程,将任务分配给该线程执行。当任务执行完毕后,线程将返回到线程池,可以被其他任务复用。

线程池是一种多线程处理模式,它允许多个线程在程序中被重用,而不是在需要的时候创建新的线程,使用完后销毁。线程池的主要目的是提高资源利用率和系统的响应速度。其运行机制就是,通过线程的复用,任务队列和池的管理来进行运行。

线程复用:通过预先创建一定数量的线程并将其保存在池中,避免了频繁创建和销毁线程的开销。当有任务需要执行时,从线程池中取出一个空闲线程来执行任务,任务完成后线程回到池中等待下一个任务。
任务队列:当所有线程都在忙碌时,新的任务会被放入队列中等待空闲线程来处理。
池的管理:线程池会自动管理线程的生命周期,包括线程的创建、执行和销毁,确保系统资源的高效利用。

其优势主要有:
提高性能:减少了线程创建和销毁的开销,因为创建和销毁线程是昂贵的操作。
控制并发量:通过限制线程池中的最大线程数量,可以避免过多的线程导致系统资源耗尽。
提高资源利用率:通过线程复用,提高CPU和内存的使用效率。
便于管理:通过线程池,统一管理和调度线程,简化了并发程序的开发。

当然,线程池也存在着其局限性:

1.需要进行线程池配置,而线程池的配置,决定着线程池的性能和效果的好坏。他需要你根据具体的场景进行动态的更改配置去进行优化,从而保证其性能和效果实现最大化。

2.死锁:如果一个任务在执行过程中需要等待另一个任务完成,而后者又需要第一个任务完成某些操作,这样的循环依赖会导致死锁。

3.资源泄漏:如果线程池没有正确关闭(调用shutdown或shutdownNow方法),可能会导致线程池中的线程一直存在,造成资源泄漏

4.任务饥饿:如果线程池的任务队列中的任务被长时间占用,新的任务可能无法及时得到处理。这种情况被称为“任务饥饿”,可能会导致系统响应缓慢。

5. 资源消耗:线程池在创建时会初始化一组线程,这些线程会一直占用系统资源(如内存和CPU),即使它们处于空闲状态。这可能会在高负载系统中导致资源浪费

2.线程池的创建和销毁

1. 使用 Executors 工具类
1.1Executors类提供了一些静态工厂方法来方便地创建几种常用的线程池:

//创建一个固定大小的线程池

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

1.2:提交任务:使用execute()submit()方法将任务提交给线程池。

executor.execute(new MyRunnable()); // 提交Runnable任务
Future<String> future = executor.submit(new MyCallable()); // 提交Callable任务,并返回Future对象

1.3:销毁任务(关闭线程):

executor.shutdown();

2.使用 ThreadPoolExecutor 类

int corePoolSize = 5;//线程核心,不能少于0

int maximumPoolSize = 10;//最大线程的数量

long keepAliveTime = 1;//非核心线程的空闲存活时间设置为1分钟。非核心线程是超过corePoolSize创建的线程

TimeUnit unit = TimeUnit.MINUTES;//设置存活时间的单位,这里是分钟。  

创建一个有界的工作队列,容量为100。当线程池中的线程都在忙碌时,新的任务会被放入这个队列中等待执行。  

BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);

//创建一个ThreadPoolExecutor实例

ThreadPoolExecutor customThreadPool = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);

3.线程和进程的区别

进程(Process):进程就像是马路上的一辆辆汽车。每一辆汽车都是一个独立的个体。进程是系统进行资源分配和调度的基本单位。当你启动一个程序(比如打开一个浏览器或者一个文本编辑器),系统就会为这个程序分配一定的资源(如内存空间),并创建一个进程来运行这个程序。

线程(Thread):线程就像是汽车里的司机。一个进程可以包含多个线程,这些线程共享进程的资源(一辆汽车里可以有多个司机,每个司机都负责驾驶汽车的一部分路程。同样地,一个进程中的多个线程可以并行执行不同的任务,共享进程的内存空间,但各自有独立的执行路径。

4.synchronized

synchronized 是 Java 语言中的一个关键字,它用于实现线程间的同步(synchronization),即控制多个线程对共享资源的访问。当一个线程访问某个对象的某个 synchronized(同步)代码块或方法时,其他线程对该对象的所有其他 synchronized 代码块或方法的访问将被阻塞,直到该线程完成其工作并退出 synchronized 块或方法。这样可以防止多个线程同时访问和修改同一共享资源,从而避免了数据不一致的问题。synchronized 锁时,我们实际上是指由 synchronized 关键字创建的一个内置锁(也称为监视器锁或互斥锁)。在Java对象中,每一个对象都有一个内置锁,当你有一个共享资源,所有的线程都要使用这个共享资源的时候,就会造成数据不一致或线程安全问题。但是你给这个共享资源加上一个锁(synchronized 锁)时,线程要去使用这个资源就要获取这个锁才能去使用共享资源,其他的线程因为没有锁就无法使用,他必须要等待这个锁被释放才行。

5.将业务和线程实现脱离

在编程中,意味着将处理业务逻辑的代码与创建和管理线程的代码分离开来。这种做法有助于提高代码的可读性、可维护性和可扩展性。将业务逻辑(即应用程序的实际功能和数据处理部分)与线程管理(即控制和管理线程的执行和调度的部分)进行解耦或分离。这种分离的目的在于提高代码的可维护性、可扩展性和并发性能。在Java中,可以通过实现Runnable接口或继承Thread类来定义业务逻辑,并将这些任务提交给线程池(如ThreadPoolExecutor)来执行。线程池负责线程的创建、调度和管理,而业务逻辑代码则只需要关注于实现具体的业务功能。这种分离使得代码更加清晰、易于维护,并且能够更好地利用系统资源提高并发性能


 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值