java--线程池

news2024/11/17 17:54:07

目录

1.线程池概

2 为什么要使用线程池

1创建线程问题

2解决上面两个问题思路:

3线程池的好处

4线程池适合应用场景

3 线程池的构造函数参数

1.corePoolSize int 线程池核心线程大小

2.maximumPoolSize int 线程池最大线程数量

3.keepAliveTime long 空闲线程存活时间

4.unit 空闲线程存活时间单位

5.workQueue  BlockingQueue 工作队列

①ArrayBlockingQueue

②LinkedBlockingQuene

③SynchronousQuene

④PriorityBlockingQueue

6.threadFactory ThreadFactory  线程工厂       

7.handler RejectedExecutionHandler 拒绝策略

①CallerRunsPolicy

 8.添加线程例子

例如饭店的桌子的故事:

线程池的而实际例子:

4增减线程的特点

5线程池手动创建还是自动创建

1自动创建好处

2自动创建可能带来哪些问题

1.newFixedThreadPool

2.newSingleThreadExecutor

 3.newCachedThreadPool

3正确创建线程池的方法

4线程池里的线程数量设定多少比较适合

6停止线程的正确方法

1.shutdown

 2isShutdown

3.isTerminated

4.awaitTermination

5.shutdownNow

7.线程池拒绝策略

1.拒绝时机

2.四种拒绝策略

1.概述

8.钩子方法

1.每个任务执行之前之后暂停恢复模拟日志、统计

9.线程池原理

1.线程池组成部分

2.线程管理器

3.工作线程

4.任务列队

5.任务接口


1.线程池概

软件中的池,就是提前创建好了东西放在池子里,你直接去池子里拿去用就行了,有现成的可用的,节省了你临时创建的时间。
我们的资源是有限的,比如就10个线程,创造一个10个线程的线程池。
线程池中创建的线程,可以重复使用,可以控制资源总量。

如果不使用线程池,每个任务都开一个新线程处理
1.1个线程
2.for循环创建线程
3.当任务量生成1000个时

public class EveryTaskOneThread {
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            Thread thread = new Thread(new Task());
            thread.start();
        }
    }

   static class Task implements Runnable{

        @Override
        public void run() {
            System.out.println("执行了任务!");
        }
    }
}
这样开销太大,我们希望有固定数量的线程,
来执行这1000个线程,
这样就避免了反复创建并销毁线程所带来的开销问题。

2 为什么要使用线程池

1创建线程问题

  • 反复创建线程开销大
  • 过多的线程会占用大多内存

2解决上面两个问题思路:

  • 用少量线程-避免内存占用过多
  • 让这部分线程都保持工作,且可以反复执行任务-避免生命周期的损耗

3线程池的好处

  • 加快响应速度
  • 合理利用CPU和内存
  • 统一归管理资源

4线程池适合应用场景

  • 服务器接收大量请求时,使用线程池 是非常合适的,他可以大大减少线程池的创建和销毁次数,提高服务器的工作效率
  • 实际开发中,如果需要创建5个以上的线程,那么就可以使用线程池来管理

3 线程池的构造函数参数

1.corePoolSize int 线程池核心线程大小

线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。任务提交到线程池后,首先会检查当前线程数是否达到了corePoolSize,如果没有达到的话,则会创建一个新线程来处理这个任务。

是否需要添加线程规则

 

2.maximumPoolSize int 线程池最大线程数量

当前线程数达到corePoolSize后,如果继续有任务被提交到线程池,会将任务缓存到工作队列(后面会介绍)中。如果队列也已满,则会去创建一个新线程来出来这个处理。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。

3.keepAliveTime long 空闲线程存活时间

一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定

4.unit 空闲线程存活时间单位

keepAliveTime的计量单位 

5.workQueue  BlockingQueue 工作队列

新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列: 

①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而基本不会去创建新线程直到maxPoolSize(很难达到Interger.MAX这个数),因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

④PriorityBlockingQueue

具有优先级的无界阻塞队列,优先级通过参数Comparator实现。

6.threadFactory ThreadFactory  线程工厂       

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

新的线程是由ThreadFactory创建的,默认使用Executors.defaultThreadFactory0,创建出来的线程都在同个线程组,拥有同样的NORM PRIORITY优先级并且都不是守护线程。如果自己指定ThreadFactory,那么就可以改变线程名、线程组、优先级、是否是守护线程等

通常使用默认的即可

7.handler RejectedExecutionHandler 拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略: 

①CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

②AbortPolicy

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。

③DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

④DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

 8.添加线程例子

例如饭店的桌子的故事:

饭店屋子里面10个桌子,这10个桌子是一直存在的。是corePoolSize。
生意火爆,里面桌子坐满了,需要使用临时桌子,放到饭店门口。是maxPoolSize。

在收摊的时候外面的椅子会收回来的。里面的桌子不会处理,一直会等待。

线程池的而实际例子:

线程池:核心池大小5,最大池大小为10,队列为100

线程池中的请求最多创建5个,然后任务被添加到队列中,直到达到100.当队列已满时,将创建最新的线程。maxPoolSize。最多10个线程,如果再来任务,就拒绝。

4增减线程的特点

  • 通过设置corePoolSize和maximunPoolSize相同,就可以创建固定大小的线程池
  • 线程池希望保持更小的线程数量,并且只有在负载变得很大的时候才去增加他
  • 通过设置maximunPoolSize为很高的值,可以允许线程池容纳任意数量的并发任务
  • 只有队列满的时才会创建多余corePoolSize的线程,如果使用无界队列(LinkedBlockingQueue),那么线程数就不会超过corePoolSize

 

5线程池手动创建还是自动创建

1自动创建好处

  • 手动创建更好,因为这样可以让我们更加明确线程池创建的规则,避免资源耗尽的风险。

2自动创建可能带来哪些问题

1.newFixedThreadPool

传进去的LinkedBlockingQueue是没有容量限制的,所以当请求数量越来越多。并且无法及时处理完的时候,也就会请求堆积,会很容易造成占用大量内存。可能会导致oom

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 100; i++) {
            executorService.execute(new Task());
        }
    }
    static class Task implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread());
        }
    }
}

错误案例

修改idea内存配置 -Xmx1m -Xms1m

 没有点击Modify options,然后add即可

应用之后启动下面代码

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示newFixedThreadPool出错的情况
 */
public class FixedThreadPoolOOMTest {
    private static   ExecutorService executorService = Executors.newFixedThreadPool(1);
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            executorService.execute(new Task());
        }
    }
    static class Task implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread());
            try {
                Thread.sleep(500000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 控制台打印如下

2.newSingleThreadExecutor

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExcutor {
    public static void main(String[] args) {
        // 单独的线程不需要传参数,线程数默认1
        /*
        * public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
           }

        * */
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 100; i++) {
            executorService.execute(new Task());
        }
    }
    static class Task implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread());
        }
    }
}

 3.newCachedThreadPool

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadExcutor {
    public static void main(String[] args) {
        // 无界线程池,具有自动回收对于线程的功能
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            executorService.execute(new Task());
        }
    }
    static class Task implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread());
        }
    }
}

3正确创建线程池的方法

  • 根据不同的业务场景,自己设置线程池参数,比如我们的内存有多大,我们想给线程取什么名字等等。

4线程池里的线程数量设定多少比较适合

创建多少线程合适,要看多线程具体的应用场景。我们的程序一般都是 CPU 计算和 I/O 操作交叉执行的,由于 I/O 设备的速度相对于 CPU 来说都很慢,所以大部分情况下,I/O 操作执行的时间相对于 CPU 计算来说都非常长,这种场景我们一般都称为 I/O 密集型计算;和 I/O 密集型计算相对的就是 CPU 密集型计算了,CPU 密集型计算大部分场景下都是纯 CPU 计算。I/O 密集型程序和 CPU 密集型程序,计算最佳线程数的方法是不同的。
下面我们对这两个场景分别说明。
对于 CPU 密集型计算,多线程本质上是提升多核 CPU 的利用率,所以对于一个 4 核的 CPU,每个核一个线程,理论上创建 4 个线程就可以了,再多创建线程也只是增加线程切换的成本。所以,对于 CPU 密集型的计算场景,理论上“线程的数量 =CPU 核数”就是最合适的。不过在工程上,线程的数量一般会设置为“CPU 核数 +1”,这样的话,当线程因为偶尔的内存页失效或其他原因导致阻塞时,这个额外的线程可以顶上,从而保证 CPU 的利用率。
对于 I/O 密集型的计算场景,比如前面我们的例子中,如果 CPU 计算和 I/O 操作的耗时是 1:1,那么 2 个线程是最合适的。如果 CPU 计算和 I/O 操作的耗时是 1:2,那多少个线程合适呢?是 3 个线程,如下图所示:CPU 在 A、B、C 三个线程之间切换,对于线程 A,当 CPU 从 B、C 切换回来时,线程 A 正好执行完 I/O 操作。这样 CPU 和 I/O 设备的利用率都达到了 100%。

CPU密集型(加密、计算hash等): 最佳线程数为CPU核心数的1-2倍左右。

耗时IO型(读写数据库、文件、网络读写等):最佳线程数般会大于cpu核心数很多倍,以JVM线程监控显示繁忙情况头依据,保证线程空闲可以衔接上

参考Brain Goetz推荐最终终计算方法: 线程数=CPU核心数*( 1+平均等待时间/平均工作时间)

6停止线程的正确方法

1.shutdown

对于线程池而言,拒绝后面新的的任务,存量任务执行完会关闭

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示关闭线程
 */
public class ShuntDown {
    public static void main(String[] args) throws InterruptedException {
        // 创建10个固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new ShuntDownTask());
        }
        Thread.sleep(500);
        executorService.shutdown();
        // 再提交新的任务,提交不进去
        for (int i = 0; i < 1000; i++) {
            executorService.execute(new ShuntDownTask());
        }

    }
    static class ShuntDownTask implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

控制台打印,可以看到后面的任务没有被执行

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task cn.butool.threadpool.ShuntDown$ShuntDownTask@29453f44 rejected from java.util.concurrent.ThreadPoolExecutor@5cad8086[Shutting down, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at cn.butool.threadpool.ShuntDown.main(ShuntDown.java:20)
pool-1-thread-9
pool-1-thread-1
pool-1-thread-2
pool-1-thread-5
pool-1-thread-6
pool-1-thread-3
pool-1-thread-4
pool-1-thread-8
pool-1-thread-7
pool-1-thread-10

Process finished with exit code 1

 2isShutdown

isShutDown当调用shutdown()方法后返回为true。

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示关闭线程
 */
public class ShuntDown {
    public static void main(String[] args) throws InterruptedException {
        // 创建10个固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new ShuntDownTask());
        }
        Thread.sleep(500);
        System.out.println(executorService.isShutdown());
        executorService.shutdown();
        System.out.println(executorService.isShutdown());

    }
    static class ShuntDownTask implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
pool-1-thread-2
pool-1-thread-5
pool-1-thread-6
pool-1-thread-10
pool-1-thread-9
pool-1-thread-1
pool-1-thread-4
pool-1-thread-7
pool-1-thread-8
false
pool-1-thread-3
true

3.isTerminated

isTerminated当调用shutdown()方法后,并且所有提交的任务完成后返回为true

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示关闭线程
 */
public class ShuntDown {
    public static void main(String[] args) throws InterruptedException {
        // 创建10个固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new ShuntDownTask());
        }
        Thread.sleep(500);
        System.out.println(executorService.isShutdown());
        executorService.shutdown();
        System.out.println(executorService.isTerminated());

    }
    static class ShuntDownTask implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

打印

pool-1-thread-10
pool-1-thread-3
pool-1-thread-4
pool-1-thread-7
pool-1-thread-8
false
pool-1-thread-9
pool-1-thread-6
false
pool-1-thread-5
pool-1-thread-2
pool-1-thread-1

缩小任务查看

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示关闭线程
 */
public class ShuntDown {
    public static void main(String[] args) throws InterruptedException {
        // 创建10个固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 1; i++) {
            executorService.execute(new ShuntDownTask());
        }
        Thread.sleep(500);
        System.out.println(executorService.isShutdown());
        executorService.shutdown();
        System.out.println(executorService.isTerminated());

    }
    static class ShuntDownTask implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

打印

false
pool-1-thread-1
true

4.awaitTermination

有时场景需要主线程等各子线程都运行完毕后再执行。这时候就需要用到ExecutorService接口中的awaitTermination方法

package cn.butool.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 演示关闭线程
 */
public class ShuntDown {
    public static void main(String[] args) throws InterruptedException {
        // 创建10个固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(new ShuntDownTask());
        }
        Thread.sleep(500);
        executorService.shutdown();
        //该方法调用会被阻塞,并且在以下几种情况任意一种发生时都会导致该方法的执行:
        // 即shutdown方法被调用之后,或者参数中定义的timeout时间到达或者当前线程被打断,
        // 这几种情况任意一个发生了都会导致该方法在所有任务完成之后才执行。
        // 第一个参数是long类型的超时时间,第二个参数可以为该时间指定单位。
        System.out.println(executorService.awaitTermination(3, TimeUnit.SECONDS));

    }
    static class ShuntDownTask implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
控制台打印
pool-1-thread-2
pool-1-thread-3
pool-1-thread-7
pool-1-thread-6
pool-1-thread-4
pool-1-thread-8
pool-1-thread-5
pool-1-thread-1
pool-1-thread-9
pool-1-thread-10
true

Process finished with exit code 0

5.shutdownNow

shutdownNow调用的是中断所有的Workers,shutdownNow会把所有任务队列中的任务取出来,返回一个任务列表。

package cn.butool.threadpool;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 演示关闭线程
 */
public class ShuntDown {
    public static void main(String[] args) throws InterruptedException {
        // 创建10个固定的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 100; i++) {
            executorService.execute(new ShuntDownTask());
        }
        Thread.sleep(1500);
        // 立刻关闭掉线程池,返会没有执行的任务列表
        List<Runnable> runnables = executorService.shutdownNow();
        System.out.println("被中断数量"+runnables.size());
    }
    static class ShuntDownTask implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(500);
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                System.out.println("被中断了"+Thread.currentThread().getName());
            }
        }
    }
}

控制台打印

pool-1-thread-3
pool-1-thread-9
pool-1-thread-10
pool-1-thread-6
pool-1-thread-5
pool-1-thread-2
pool-1-thread-1
pool-1-thread-8
pool-1-thread-7
pool-1-thread-4
pool-1-thread-3
pool-1-thread-1
pool-1-thread-4
pool-1-thread-9
pool-1-thread-10
pool-1-thread-6
pool-1-thread-5
pool-1-thread-2
pool-1-thread-8
pool-1-thread-7
被中断了pool-1-thread-7
被中断了pool-1-thread-5
被中断了pool-1-thread-6
被中断了pool-1-thread-9
被中断了pool-1-thread-3
被中断了pool-1-thread-1
被中断了pool-1-thread-2
被中断了pool-1-thread-10
被中断了pool-1-thread-4
被中断了pool-1-thread-8
被中断数量70

Process finished with exit code 0

7.线程池拒绝策略

1.拒绝时机

  • Executors关闭时提交新任务会拒绝
  • Executors最大线程和工作队列容量使用优先边界并且已经饱和

2.四种拒绝策略

1.概述

  拒绝策略提供顶级接口 RejectedExecutionHandler ,其中方法 rejectedExecution 即定制具体的拒绝策略的执行逻辑。
jdk默认提供了四种拒绝策略

2.AbortPolicy - 抛出异常,中止任务。抛出拒绝执行 RejectedExecutionException 异常信息。线程池默认的拒绝策略。必须处理好抛出的异常,否则会打断当前的执行流程,影响后续的任务执行

3.CallerRunsPolicy - 使用调用线程执行任务。当触发拒绝策略,只要线程池没有关闭的话,则使用调用线程直接运行任务。一般并发比较小,性能要求不高,不允许失败。但是,由于调用者自己运行任务,如果任务提交速度过快,可能导致程序阻塞,性能效率上必然的损失较大

4.DiscardPolicy - 直接丢弃,其他啥都没有

5.DiscardOldestPolicy - 丢弃队列最老任务,添加新任务。当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入

8.钩子方法

1.每个任务执行之前之后暂停恢复模拟日志、统计

package cn.butool.threadpool;


import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 每个任务执行的前后放钩子函数
 */
public class SuspendThreadPoolTest extends ThreadPoolExecutor {
    public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public SuspendThreadPoolTest(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * 重写方法
     * @param t
     * @param r
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        lock.lock();
        try {
            while (isPaused){

                unPaused.await();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private boolean isPaused;

    private final ReentrantLock lock= new ReentrantLock();
    private Condition unPaused=lock.newCondition();

    private void usePaused(){
        // 枷锁
        lock.lock();
        try {
            isPaused=true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    /**
     * 恢复函数
     */
    private void resume(){
        // 枷锁
        lock.lock();
        try {
            isPaused=false;
            unPaused.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();


        }
    }

    public static void main(String[] args) throws InterruptedException {
        SuspendThreadPoolTest suspendThreadPoolTest = new SuspendThreadPoolTest(5,
                10,
                20,TimeUnit.SECONDS,
                new LinkedBlockingDeque<>());
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("我被执行"+Thread.currentThread().getName());

                try {
                    Thread.sleep(10);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {

                }
            }
        };
        for (int i = 0; i < 10000; i++) {
            suspendThreadPoolTest.execute(runnable);
        }
        Thread.sleep(1500);
        //线程池暂停
        suspendThreadPoolTest.usePaused();
        System.out.println("线程池被暂停了");
        Thread.sleep(1500);
        suspendThreadPoolTest.resume();
        System.out.println("线程池被恢复了");
    }
}

9.线程池原理

1.线程池组成部分

1.线程管理器

2.工作线程

3.任务列队

4.任务接口

2.线程管理器

3.工作线程

4.任务列队

5.任务接口


                

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/445415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Centos elasticsearch 8.7.0 集群搭建

Install Elasticsearch with RPM | Elasticsearch Guide [8.7] | Elastic 准备了3台centos&#xff0c;ip分别是&#xff1a; 1、192.168.1.103 2、192.168.1.148 3、192.168.1.192 开始安装第1个节点 1、 rpm --import https://artifacts.elastic.co/GPG-KEY-elasticse…

快速引用网站标题链接到Markdown

JS脚本 将JS脚本添加到书签栏&#xff0c;通过调用书签栏执行快速复制网页标题和链接 合成Markdown格式的方法&#xff1a; javascript:!function(a){var b document.createElement("textarea"),c document.getSelection();(b.textContent a),document.body.ap…

【C++】STL——vector 深度剖析 及 模拟实现

文章目录 前言1. vector的介绍及使用1.1 vector的介绍1.2 vector的使用1.2.1 构造函数1.2.2 vector对象的遍历1.2.3 vector的迭代器1.2.4 reserve和resize1.2.5 insert和erase1.2.6 vector< char > 能否替代string 2. vector的模拟实现2.1 STL_vector源码浏览2.2 vector的…

网络安全-网站后台的寻找+网页JS文件信息收集

网络安全-网站后台的寻找网页JS文件信息收集 前言 一&#xff0c;我也是初学者记录的笔记 二&#xff0c;可能有错误的地方&#xff0c;请谨慎 三&#xff0c;欢迎各路大神指教 四&#xff0c;任何文章仅作为学习使用 五&#xff0c;学习网络安全知识请勿适用于违法行为 学习网…

数影周报:美联邦机构被曝数据泄露丑闻,嘀嗒狗完成数千万元融资

本周看点&#xff1a;美联邦下属机构超25万消费者隐私被泄露&#xff1b;钉钉、金山办公同日公布AI应用&#xff1b;京东全球购与宿迁市港口集团签订战略协议&#xff1b;嘀嗒狗完成数千万元Pre-A轮融资...... 数据安全那些事 美联邦机构被曝数据泄露丑闻 海外网4月20日电 据美…

DeepSORT中的卡尔曼滤波

本文是看了DeepSORT方法视频之后&#xff0c;关于其中使用的卡尔曼滤波的理解 DeepSORT视频链接 首先是视频中的一张图 预测阶段 x ^ k − A x ^ k − 1 \hat{x}_k^-A\hat{x}_{k-1} x^k−​Ax^k−1​ P k − A P k − 1 Q , P k − ∈ R 8 , 8 P_k^-AP_{k-1}Q, P_k^- \i…

Python轻量级Web框架Flask(10)——Flask进阶知识

1、Flask整体框架流程回顾&#xff1a; 视图函数把数据返回给浏览器的方法有多种&#xff0c;其中一种就是通过模板Templates。 2、Flask插件介绍&#xff1a; Flask插件可以去官网查看&#xff0c;有很多。插件安装流程&#xff1a; 1、通过pip指令在对应环境中下载插件2、在…

【Python入门】NumPy 入门知识介绍,看这一篇足矣

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 什么是 NumPy&#xff1f; NumPy 是用于处理数组的 python 库。 它还拥有在线性代数、傅立叶变换和矩阵领域中工作的函数。 NumPy 由 Travis Oliphant 于 2005 年创建。它是一个开源项目&#xff0c;你可以自由使用它。 …

SAP 性能监控工具

SAP 体系结构可能很复杂&#xff0c;因为它由许多不同的元素和多层应用程序组成。每个元素都必须以最佳方式执行&#xff0c;以确保响应迅速且可靠的服务级别。管理如此复杂的系统可能非常艰巨&#xff0c;这就是为什么使用强大的SAP监控工具绝对必要的原因。 什么是 SAP 监控 …

安装autogpt中出现的问题及安装autogpt的小白教程

ImportError: DLL load failed while importing numpy_ops: The specified module could not be found 解决方案&#xff1a;Latest supported Visual C Redistributable downloads | Microsoft Learn 安装一下这个软件即可&#xff0c; 要安装 Auto-GPT&#xff0c;请按照下…

【Operating Systems:Three Easy Pieces 操作系统导论 】 4 ~ 6 章 (进程 | 进程 API | 受限直接执行)

【读书笔记】 Operating Systems:Three Easy Pieces 操作系统导论 第四章、 抽象 &#xff1a; 进程 4.1 什么是进程 ? 操作系统为正在运行的程序提供的抽象进程可以访问的内存&#xff08;称为地址空间&#xff0c;address space&#xff09; 是该进程的一部分。进程的机器…

python+nodejs+ssm+vue 基于协同过滤的旅游推荐系统

本文首先介绍了旅游推荐的发展背景与发展现状&#xff0c;然后遵循软件常规开发流程&#xff0c;首先针对系统选取适用的语言和开发平台&#xff0c;根据需求分析制定模块并设计数据库结构&#xff0c;再根据系统总体功能模块的设计绘制系统的功能模块图&#xff0c;流程图以及…

WPF教程(八)--数据绑定(1)

使用WPF可以很方便的设计出强大的用户界面&#xff0c;同时 WPF提供了数据绑定功能。WPF的数据绑定跟Winform与ASP.NET中的数据绑定功能类似&#xff0c;但也有所不同&#xff0c;在 WPF中以通过后台代码绑定、前台XAML中进行绑定&#xff0c;或者两者组合的方式进行数据绑定。…

VUE基本使用详解

目录 一、VUE框架原理 1. 了解VUE框架 2. VUE框架原理 3. MVC设计模式 4. MVVM设计模式 二、引入VUE框架 1. 本地引入 2. 网络引入 三、安装Vue插件 一、VUE框架原理 1. 了解VUE框架 vue 框架 是基于MVVM设计模式的前端框架&#xff0c;其中的Vue对象是MVVM设计模式中的VM视图…

JavaWeb——TCP协议的相关特性

目录 一、TCP 1、特性 2、确认应答 &#xff08;1&#xff09;、定义 &#xff08;2&#xff09;、原理 &#xff08;3&#xff09;、接收缓冲区 3、超时重传 &#xff08;1&#xff09;、丢包 &#xff08;2&#xff09;、定义 &#xff08;3&#xff09;、分类 二、…

idea在main分支上新建其他分支并同步过去

前言&#xff1a;首先得知道以上&#xff08;idea 版本为2021.1.3 &#xff0c;右下角git分支部分&#xff09;是什么含义。 local Branches 本地分支&#xff0c;代表当前项目路径下所存在的本地分支&#xff0c;以上是有三个,都存在与本地仓库 Remote Branches 远程分支&…

腾讯云服务器:轻量应用服务器、云服务器CVM和GPU云服务器配置表

目前腾讯云服务器分为轻量应用服务器、云服务器云服务器云服务器CVM和GPU云服务器&#xff0c;首先介绍一下这三种服务器。 1、腾讯云云服务器&#xff08;Cloud Virtual Machine&#xff0c;CVM&#xff09;提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源&#x…

进程虚拟地址空间划分

任何编程语言->产生指令和数据 我们以x86 32位linux 作为知识介绍的背景 编译后生成exe文件在磁盘上&#xff0c;需要加载到内存才能运行 但不能直接加载到物理内存 linux给当前进程分配一个2^32大小的一块空间&#xff0c;4G 虚拟地址空间解释 它存在&#xff0c;你看得…

背包问题——01背包|完全背包

目录 前言&背包问题的历史 01背包 1、题目 2、暴力解01背包 Ⅰ、代码 3、动态规划解01背包 Ⅰ、二维dp数组解01背包 1&#xff09;dp数组的含义 2&#xff09;递推公式 3&#xff09;dp数组的初始化 4&#xff09;遍历顺序的讨论 5、代码 Ⅱ、一维数组解01背包 1&…

HCLE----atd以及备份方式

atd是一种基于时间的任务调度器&#xff0c;可以在指定时间执行一次性任务。atd启动时会读取/etc/at.allow和/etc/at.deny两个文件&#xff0c;来决定哪些用户有权限使用at命令提交任务。crond是一种周期性任务调度器&#xff0c;可以按照指定的时间间隔执行重复性任务。crond启…