java--线程池

线程池,面试 首先来了5个任务,都是核心线程数在处理,第6个任务来了之后就去队列排队,,第16个任务来了之后就会创建临时线程,第21个任务来了之后就会触发handler拒绝策略。最大线程数当核心线程数到达上线后还有任务过来,那就继续创建临时线程,总共加起来的最大数。handler拒绝策略,当线程数量和队列都满之后,有新的任务过来的策略。可缓存线程池线程数量超过处理就回收线程,不超过就创建线程。比如有5个核心线程数,10个最大线程数,阻塞队列长度=10。核心线程数线程池的常驻线程数量。... 阅读详情

目录

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.线程池如何实现线程复用的

  • 相同的线程执行不同的任务

源码

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
       /*

*分三步进行:

*

* 1. 如果运行的线程少于corePoolSize,请尝试

*以给定的命令作为第一个命令启动一个新线程

*任务。对addWorker的调用原子地检查runState和

*workerCount,这样可以防止错误警报

*在不应该执行的情况下执行线程,返回false。

*

* 2. 如果任务可以成功排队,那么我们仍然需要

*仔细检查我们是否应该添加一个线程

*(因为自上次检查以来已有的死亡)或

*池在进入此方法后关闭。所以我们

*重新检查状态,并在必要时回滚排队

*已停止,或者在没有线程的情况下启动一个新线程。

*

* 3. 如果我们不能对任务进行排队,那么我们尝试添加一个新的

*螺纹。如果它失败了,我们就知道我们已经关闭或饱和了

*因此拒绝该任务。

*/


        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

增加worker核心方法

/*
     * Methods for creating, running and cleaning up after workers
     */

    /**

*检查是否可以相对于当前工作人员添加新工作人员

*池状态和给定的界限(核心或最大值)。如果是,

*相应地调整工人人数,如果可能的话

*将创建并启动新的辅助进程,并将firstTask作为其

*第一项任务。如果池已停止或

*有资格关闭。如果线程

*当被要求时,工厂无法创建线程。如果螺纹

*创建失败,可能是由于线程工厂返回

*null,或由于异常(通常为中的OutOfMemoryError

*Thread.start()),我们干净地回滚。

*

*@param firstTask新线程应该首先运行的任务(或

*如果没有,则为null)。工人是用最初的第一个任务创建的

*(在方法execute()中),以在数量较少时绕过排队

*比corePoolSize线程(在这种情况下,我们总是启动一个线程),

*或者当队列已满时(在这种情况下,我们必须绕过队列)。

*最初的空闲线程通常通过

*prestartCoreThread或替换其他垂死的工人。

*

*@param core如果为true,则使用corePoolSize作为绑定,否则

*最大池大小。(此处使用布尔指示符,而不是

*值,以确保在检查其他池后读取新值

*州)。

*@如果成功,返回true

*/
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

worker核心类,调用runWorker方法实现了线程复用;

/**

Class Worker主要维护运行任务的线程的中断控制状态,以及其他次要的记账。此类机会主义地扩展了AbstractQueuedSynchronizer,以简化获取和释放每个任务执行周围的锁。这可以防止旨在唤醒等待任务的工作线程而不是中断正在运行的任务的中断。我们实现了一个简单的非重入互斥锁,而不是使用ReentrantLock,因为我们不希望工作任务在调用诸如setCorePoolSize之类的池控制方法时能够重新获取锁。此外,为了在线程真正开始运行任务之前抑制中断,我们将锁定状态初始化为负值,并在启动时清除它(在runWorker中)。
*/

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

runWorker

/*主要工人运行循环。重复地从队列中获取任务并执行它们,
同时处理许多问题:
1。我们可以从一个初始任务开始,在这种情况下,
我们不需要获得第一个任务。否则,只要池正在运行,
我们就会从getTask获得任务。如果返回null,
则工作进程将由于池状态或配置参数的更改而退出。
其他退出是由外部代码中的异常抛出引起的,
在这种情况下,completedAbruptly保持不变,
这通常会导致processWorkerExit替换此线程。
2.在运行任何任务之前,获取锁以防止任务执行时其他池中断,
然后我们确保除非池停止,否则此线程不会设置中断。
3.每次任务运行之前都会调用beforeExecute,
这可能会引发异常,在这种情况下,
我们会导致线程在不处理任务的情况下死亡(用completedAbruptly true中断循环)。
4.假设beforeExecute正常完成,我们运行任务,
收集它抛出的任何异常,发送到afterExecute。
我们分别处理RuntimeException、Error(规范保证我们捕获这两者)和任意Throwables。
因为我们无法在Runnable.run中重新抛出Throwables,所以我们将它们封装在退出时的
Errors中(到线程的UncaughtException Handler)。
任何抛出的异常也会保守地导致线程死亡。
5.task.run完成后,我们调用afterExecute,
它也可能抛出异常,这也会导致线程死亡。
根据JLS Sec 14.20,即使task.run抛出,
这个异常也将生效。
异常机制的净效果是afterExecute和线程的UncaughtException处理程序
具有我们所能提供的关于用户代码遇到的任何问题的准确信息。

参数:

w–工人*/
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                
    
            //如果池正在停止,请确保线程被中断;

            //如果没有,请确保线程没有中断。这

            //第二种情况需要重新检查才能处理

            //shutdown清除中断时无竞争
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

浅谈Java线程池,Java线程池解析。 掌握线程池是后端程序员的基本要求,相信大家求职面试过程中,几乎都会被问到有关于线程池的问题。我在网上搜集了几道经典的线程池面试题,并以此为切入点,谈谈我对线程池的理解。如果有哪里理解不正确,非常希望大家指出,接下来大家一起分析学习吧。 阅读详情

相关推荐

非凸问题的求解方法以及连续凸逼近SCA(Successive Convex Approximation)方法

非凸问题的求解方法 针对形如下式的函数: min⁡x∈XV(x)=F(x)+G(x)\min\limits_{{\bf{x}}\in X} V(x)=F(x)+G(x)x∈Xmin​V(x)=F(x)+G(x); 其中F为光滑的(不一定convex),G是convex的但是可能不可微,且存在:对于n维实矢量空间,有X=X1×...×XNX=X_1 \times...\times X_NX=X1​×...×XN​; x=(x1,...,xN)\bf{x} =(x_1,...,x_N)x=(x1​,...,xN

weixin_44535200的博客 2万+

【线程池】Java线程池的核心参数

一篇文章带你快速了解Java线程池的核心参数

小七的博客 7710

保姆级教程:用GMT6.1绘制专业地形起伏图(从数据下载到出图避坑)

本文提供了一份详细的GMT6.1绘制地形起伏图的保姆级教程,从环境搭建到数据下载,再到核心绘图命令解析,帮助用户避开常见错误。特别适合科研人员和地理信息爱好者快速掌握专业地形图的绘制技巧,提升工作效率。

weixin_42549723的博客 275

Java线程池ThreadPoolExecutor的7个参数详解

下面是对的七个参数的详细解释:核心线程数(corePoolSize):核心线程数是线程池中保持活动状态的线程数。即使没有任务需要执行,核心线程也不会被回收。当有新任务提交时,如果核心线程都在忙碌,则会创建新的线程来处理任务。最大线程数(maximumPoolSize):最大线程数是线程池中允许的最大线程数。当工作队列满了并且活动线程数达到最大线程数时,如果还有新任务提交,线程池将创建新的线程来处理任务。但是,超过最大线程数的线程可能会导致资源消耗过大。

学亮编程手记 4400

HFSS新手避坑指南:从零搭建T形波导功分器(含参数扫描与优化实战)

本文为HFSS新手提供T形波导功分器设计的详细指南,涵盖基础设置、建模技巧、参数扫描与优化实战。重点解析内场分析中的常见陷阱,如单位设置、波端口定义和布尔运算错误,并分享优化设计的关键步骤,帮助工程师快速掌握HFSS在微波器件设计中的应用。

weixin_27442001的博客 138

更多 LSTM 变种——应用于 CMAPSS 数据集

本文并模型介绍,只是把一些比较火的技术,像双向注意力机制,自注意力机制这样的比较火的内容,简单的和LSTM堆叠,结果发现效果都不如最基础的,这里作者将本人代码及实现结果,进行展示,给各位想更改LSTM的朋友一些。

2301_77491330的博客 1765

Java线程池七个参数详解:核心线程数、最大线程数、空闲线程存活时间、时间单位、工作队列、线程工厂、拒绝策略

源码简介 ThreadPoolExecutor是JDK中的线程池实现,这个类实现了一个线程池需要的各个方法,它实现了任务提交、线程管理、监控等等方法。 来看看ThreadPoolExecutor类的构造方法源码,其他创建线程池的方法最终都会导向这个构造方法。共有7个参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler,下面将对这7个参数展开讲解。 public ThreadPool

xzh_blog 6万+

人工势场法三大致命缺陷?我用ROS+Gazebo做了组对比实验

本文通过ROS与Gazebo仿真实验,深入剖析了人工势场法(APF)在机器人路径规划中的三大经典问题:局部最小值、目标不可达和路径震荡。文章不仅复现了这些缺陷,还对比测试了虚拟目标点法、改进斥力场及运动平滑等主流改进方案,为工程选型提供了基于数据的实用建议。

dapp9builder的博客 215

Java线程池的七个参数

最大线程数,是指线程池允许创建的最大线程数量。线程池创建线城市调用的工厂方法,通过此方法可以设置线程的优先级、线程的命名规则以及线程的类型(用户线程还是守护线程)等。核心线程数,是指线程池中长期存活的线程数。核心线程数为 2,最大线程数为 1,报 java.lang.IllegalArgumentException 异常,但是最大线程数可以等于核心线程数。当线程池的任务超出线程池队列可以存储的最大值之后,拒绝任务的策略。阻塞队列,指线程池存放任务的队列,用来存储线程池的所有待执行的任务。

qq_47949604的博客 1224

骗分导论 CSP、NOIP、蓝桥杯、PAT、USACO等竞赛的算法骗分技巧 轻松省三

问题来了,那么多座桥,炸一座就破坏岛屿的联系,可能性微乎其微(除非特别设计数据)。它们的价值极大,不仅能初步帮你检验程序的对错,而且,如果你不会做这道题,你就可以直接输出样例!在OI考试中最后难的题数据最后的几个,他们往往不会创造新的数据,此时就可以直接输出最后几个数据了。需要运用《骗分导论》第3章中学到的知识,先写出朴素算法,然后造一些数据,可能就会发现规律。有些时候,问题的答案可能很有特点:对于大多数情况,答案是一样的。据说,在NOIP2013中,有人最后一题不会,愤然打了个随机数,结果得了。

星卯教育-信奥教练tony 6402

北斗导航 | 卫星导航接收机原理(基础)

卡尔曼滤波,最小二乘,伪距,芯片,模组,接收机,捕获,跟踪,RTK,RTD,PPP,SPP,多普勒,DOP,灵敏度,热启动,冷启动,PNT,北斗发展,MEO,IGSO,GEO,ICD,导航电文,载波,载噪比

尘世冰封的专栏 2340

spring 的线程池还是 java 的线程池

Java 提供了一个强大的并发库,其中包含了线程池的基本实现。线程池是接口的实现类,用于管理线程的创建、执行和终止。通过线程池,开发者可以避免频繁创建和销毁线程带来的开销,从而提升应用程序的性能。Spring 框架对 Java 的并发库进行了封装,使得线程池的配置更加简洁和灵活。Spring 提供了接口,这是对 JavaExecutor接口的扩展,允许开发者更容易地配置和管理线程池。Spring 的线程池配置通常通过 XML 或 Java 配置类来实现,并且 Spring 提供了多种实现,如等。

Flying_Fish_roe的博客 1673

CVPR 2026 即插即用 | 注意力篇 | MSEF:超轻注意力,空间-通道双分支并行融合,既增强特征又抑制噪声!

Multinex提出了一种超轻量级微光图像增强框架,其核心创新是MSEF模块。MSEF采用双分支并行架构,结合空间局部特征(深度可分离卷积)和全局通道注意力(改进SE),通过Tanh激活实现特征增强与抑制。相比传统注意力模块,MSEF在几乎不增加计算量的情况下显著提升性能,特别适合轻量级网络和边缘设备部署。实验表明,该模块能有效提升PSNR约3dB,同时保持极低的参数量(0.7K-45K)。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 600

Java 线程池

在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题。(1)线程池中最多执行1个线程,之后提交的线程活动将会排在队列中依次执行。(1)线程池中最多执行1个线程,之后提交的线程活动将会排在队列中依次执行。(2)线程池中的线程可进行缓存重复利用和回收。(1)线程池中的线程处于一定的量,可以很好的控制线程的并发量。(2)线程可以重复被使用,在显式关闭之前,都将一直存在。(1)线程池中具有指定数量的线程,即便是空线程也将保留。(3)当线程池中,没有可用线程,会重新创建一个线程。

ggfgfggg的博客 1065

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Java 线程池详解

Java线程池是一个管理线程的工具,它能够显著提高多线程程序的性能和可管理性。线程池是Java中用于管理和控制一组线程的机制,它可以有效地减少创建和销毁线程的开销,提高系统性能。线程池通过重复使用已存在的线程来执行新的任务,避免了频繁地创建和销毁线程所带来的资源消耗。优势特点降低资源消耗:避免过度创建线程导致的系统开销。提升响应速度:可以快速分配线程来执行任务,提高程序响应效率。增强可管理性:提供统一管理线程的手段,方便监控和调优。Executor。

weixin_42093668的博客 2070

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

java的线程池及动态线程池

Java 线程池(Thread Pool)是 Java 并发编程中的重要组件,主要用于管理和复用线程,以提高程序的并发性能、减少线程创建和销毁的开销,并防止资源耗尽。Java 提供了 包下的 框架来管理线程池。在高并发环境下,如果每个任务都创建一个新线程:Java 提供了 框架来管理线程池,其中主要的类包括: 是 Java 线程池的核心实现类,其构造方法如下: 3.1 参数解析: (核心线程数)(最大线程数) & (非核心线程存活时间 & 时间单位)(任务队列)(线程工厂)(拒绝策略)任

Hard_pea的博客 2261

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Java 线程池及线程池状态

Java 线程池及线程池状态

qq_41956014的博客 1万+

Java线程池原理及四种线程池的使用

Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执

honghailiang的专栏 1万+

java线程池

核心线程数(corePoolSize)核心线程数的设计需要根据任务的处理时间和每秒产生的任务数量来确定,例如:执行一个任务需要0.1秒,系统百分之80的时间每秒都会产生100个任务,那么要想在1秒内处理完这100个任务,就需要10个线程,此时我们就可以设计核心线程数为10;当然实际情况不可能这么平均,所以我们一般按照8082原则设计即可,既按照百分之80的情况设计核心线程数,剩下的百分之20可以利用最大线程数处理。任务队列长度(workQueue)

qq_43070052的博客 1240

Java线程池

Java线程池 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线...

weixin_41924879的博客 1188

java线程池:线程池怎么开启的、线程池怎么工作的、线程池是怎么关闭的

1.序 位于 java.util.concurrent 下的 ThreadPoolExecutor 是java的线程池,可以用来管理线程。 本文围绕线程池的开启、工作、关闭三个方向进行探究,去追溯源码的实现。 2.线程池怎么开启的 ThreadPoolExecutor 有四个构造方法,如下: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit, B.

Yuwen_forJava的博客 3789

java线程池之java自带的四种线程池

使用ThreadPoolExecutor创建线程池比较麻烦,对于很多人来说不易使用,所以java已经帮我们设计好了四种线程池。查看java源代码发现这四种线程池仍然是由ThreadPoolExecutor创建的,只不过把相关的参数已经设计好了而已。 案例一:同时演示三种线程池 /* * 任务类 */ class MyTask implements Runnable { String th

御前两把刀的专栏 1177

Java线程池使用

我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。   那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?   在Java中可以通过线程池来达到这样的效果。今天我们就...

Jbase的博客 3202

java线程池【通过源码角度看java线程池】

在查看源码之前,还是先看下整体的调用流程图,有个直观的感受。线程池提交任务的流程:调用线程池的 execute(Runnable command) 方法提交一个 Runnable 对象。首先,线程池会检查当前活跃线程的数量是否小于 corePoolSize。如果线程数小于 corePoolSize,则会创建一个新的线程来执行提交的 Runnable 任务。如果当前活跃线程数大于或等于 corePoolSize,则会尝试将 Runnable 加入到工作队列(workQueue)中。

m0_50149847的博客 1434
上一篇: nginx--HTTPS服务
下一篇: java--ThreadLocal详解
别浪呀
博客等级 码龄8年 1万+粉丝 260原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值