线程池&Lock

问题

一个线程大约占用1MB的内存空间,一个项目中我们可以创建多个线程.当项目中有多个线程,此时会占据大量的内存,甚至可能会导致内存溢出

解决思路

1,限制线程的创建数量

2,能复用的线程尽量复用

3,快速回收使用完毕的线程

线程池简介

JDK提供的对线程优化的体系,其中包含了对线程的创建,回收,复用的处理,也可以存储线程

使用线程池的主要优势
  1. 重用线程:线程池会维护一组预先创建的线程,可以重复使用它们来执行多个任务,避免了频繁创建和销毁线程的开销。

  2. 控制并发数:线程池可以限制同时执行的线程数量,防止线程过多导致系统资源耗尽。

  3. 管理线程生命周期:线程池负责创建、启动、暂停、恢复和销毁线程,简化了线程的管理和监控。

  4. 提供任务队列:线程池通常还提供一个任务队列,用于存储等待执行的任务,避免任务丢失或阻塞。

使用线程池

步骤:

  1. 创建线程池对象
  2. 提交任务给线程池执行
  3. 关闭线程池
线程池体系 

Executor(接口)
    ExecutorService(接口)
        AbstractExecutorService(抽象类)
            ThreadPoolExecutor(普通类)
        ScheduledExecutorService(接口)

Executor提供的方法

void execute(Runnable command);
作用:执行给定的线程任务

Executors作用

JDK提供方便我们创建线程池的工具类

提供创建线程的方法

创建可变线程池
   //可变线程池特点:
   //线程数量不定,
   //当线程池中没有空闲线程,该线程就会新建一个线程用于执行该任务
   //如果当空闲线程60秒时间后没有执行任务将会回收该线程
   //ExecutorService pool = Executors.newCachedThreadPool();

创建固定线程池
   //固定线程池特点:线程数量恒定
       //ExecutorService pool = Executors.newFixedThreadPool(3);

创建单例线程池
   //单例线程池:线程池中只有一个线程
   //ExecutorService pool = Executors.newSingleThreadExecutor();

创建调度线程池
   //调度线程池特点:线程池中的任务可以延迟执行,也可以延迟重复执行
   //ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

创建单例调度线程池
   //单例调度线程池特点:调度线程池只有一个线程
   //ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();

创建抢占线程池
   //特点:提高执行效率(没实现,只是构想)
   ExecutorService pool = Executors.newWorkStealingPool();

ExecutorService提供的方法

void shutdown();
    作用:关闭线程池
boolean isShutdown();
    作用:获取线程池是否关闭
boolean isTerminated();
    作用:获取线程池是否已经终止
    
Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
    作用:提交线程任务        

ThreadPoolExecutor构造函数

ThreadPoolExecutor(int corePoolSize,//核心线程数量,最小线程数量
                   int maximumPoolSize,//最大线程数量
                   long keepAliveTime,//回收时间
                   TimeUnit unit,//时间单位
                   BlockingQueue<Runnable> workQueue,//存储线程任务的队列
                   ThreadFactory threadFactory,//创建线程的工厂
                   RejectedExecutionHandler handler)//复用算法

阿里白皮书:
    为了加深对线程池的理解,建议使用ThreadPoolExecutor创建线程池
提供的方法:==
getActiveCount() :返回线程池中正在执行任务的线程数量。
getCompletedTaskCount() :返回线程池已经完成的任务数量。
getCorePoolSize() :返回线程池的核心线程数量。
getLargestPoolSize() :返回线程池曾经创建过的最大线程数量。
getPoolSize() :返回线程池当前的线程数量。
getQueue() :返回线程池的任务队列,可以通过这个方法查看任务队列的长度和内容等信息。

ScheduledExecutorService 
简介

中文名:调度线程池

特点:可以使任务延迟执行或延迟重复执行,调度线程池关闭时,其重复执行的任务也会被关闭

特有的方法

public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit)
public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit)
    作用:延迟执行
    参数:
        1,线程任务
        2,延迟时间
        3,时间单位

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                             long initialDelay,
                                             long period,
                                             TimeUnit unit)
    作用:延迟重复执行
    参数:
        1,线程任务
        2,延迟时间
        3,间隔时间
            上一次任务开始时间 - 本次任务开始时间 = 间隔时间
        4,时间单位
    注意:
        当任务执行时间大于间隔时间,此时上次任务结束时,直接开始执行本次任务
        
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                long initialDelay,
                                                long delay,
                                                TimeUnit unit)
作用:延迟重复执行
    参数:
        1,线程任务
        2,延迟时间
        3,间隔时间
            上一次任务结束时间 - 本次任务开始时间 = 间隔时间
        4,时间单位

Lock

作用:   优化锁;   更加简便的,明了的使用锁

体系与方法


    提供的方法
        void lock():关锁
        void unlock():释放锁
        Condition newCondition();//获取锁对象
    子类:
        ReentrantLock(重写锁)

Condition
    提供的方法
        void await():类似与Object提供的wait方法
        void signal();类似与Object提供的notify方法
        void signalAll();类似与Object提供的notifyAll方法

ReadWriteLock(读写锁)
    提供的方法
        Lock readLock();    获取读锁
        Lock writeLock();    获取写锁
 

   特点:
        读-读    不互斥,可以同时进行
        读-写 互斥,不能同时进行
        写-写 互斥,不能同时进行
    作用:当多个线程操作同一个数据时,提高了效率

线程优化

线程池大小的选择:
线程池大小应该根据系统处理能力和任务特性来设置。如果系统是CPU密集型,即任务需要长时间占用CPU资源,那么应该将线程池大小设置为CPU核心数,以充分利用CPU资源;如果系统是IO密集型,即任务需要等待IO操作完成才能继续执行,那么可以适当增加线程池大小,以更好地利用空闲时间处理IO操作。


队列容量的选择:
线程池的队列容量也很重要,如果队列容量太小,可能会导致任务被拒绝或者处理速度变慢;如果队列容量太大,可能会导致内存消耗过大。因此,需要根据任务的特点和系统负载情况来选择合适的队列容量。


线程池参数的调整:
线程池还有一些其他参数可以进行调整,比如线程空闲时间、拒绝策略等。线程空闲时间指的是线程在空闲一段时间后被销毁的时间阈值,可以通过设置这个参数来限制线程池中的线程数量。拒绝策略是指当线程池中的任务队列已满或无法接受新任务时,应该如何处理新任务。常见的拒绝策略包括直接抛弃、丢到调用线程执行、抛出异常等。


监控和优化:
线程池的监控和优化也非常重要,可以通过监控线程池的运行状态、任务队列长度、线程池活动线程数等指标,及时发现问题并进行优化。比如,如果发现线程池中的线程被频繁创建和销毁,可能说明线程池大小设置不合理;如果发现任务队列长度过长,可能说明线程池处理能力不足,需要增加线程池大小或者调整任务队列容量等。


总之,线程池调优需要结合具体的业务场景和系统需求进行,需要根据实际情况选择合适的线程池大小、队列容量和参数,以及进行监控和优化。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值