Java进阶笔记 线程池(类比银行业务来理解)

白话深扒JAVA线程池 —给程序员小姐姐实现了一个线程池后她竟然…… 白话深扒JAVA线程池 —给程序员小姐姐实现了一个线程池后她竟然……写在前边线程池简介线程池的选择与原因线程池执行流程四大饱和拒绝策略解析实战1:实现一个线程池实战2:RejectedExecutionHandler饱和拒绝策略的选择 写在前边 线程池是面试高频考点,本文从线程池是什么作为入口,大白话讲解线程池执行过程,扒源码判断线程池的选择,再用两个实战将线程池创建并且选择RejectedExe... 阅读详情

1. Java 线程池

线程池是一种多线程处理形式,处理过程中可以将任务(Runnable、Callable)添加到队列中,然后在创建线程后自动启动这些任务。

1.1. 线程池的特点

使用线程池可以根据系统的需求和硬件环境灵活的控制线程数量,且可以对所有线程进行统一管理,提高系统运行效率,降低系统运行压力。

  • 线程和任务分离,提升线程重用性。
  • 控制线程并发数量,降低服务器压力,统一管理所有线程。
  • 复用已有线程,节省线程创建和销毁的时间,提升系统响应速度。

1.2. Java 中的线程池类

1.3. 线程池的最佳容量

【容量影响】

  • 过小会导致程序不能充分地利用系统资源、容易导致饥饿。
  • 过大会导致更多的线程上下文切换,占用更多内存。

【CPU密集型运算】

CPU总是处于繁忙状态。通常采用CPU核数+ 1能够实现最优的CPU利用率,+1是保证当线程由于页缺失故障(操作系统)或其它原因导致暂停时,额外的这个线程就能顶上去,保证CPU时钟周期不被浪费。

【I/O密集型运算】

CPU不总是处于繁忙状态。例如,当你执行业务计算时,这时候会使用CPU资源,但当你执行I/O操作时、远程RPC调用时,包括进行数据库操作时,这时候CPU就闲下来了,你可以利用多线程提高它的利用率。

【经验公式】

线程数=核数×期望CPU利用率×CPU总时间(计算时间+等待时间)CPU计算时间线程数 = \frac {核数×期望CPU利用率×CPU总时间(计算时间+等待时间)}{CPU计算时间}线程数=CPU计算时间核数×期望CPU利用率×CPU总时间(计算时间+等待时间)​

例如4核CPU计算时间是50%,其它等待时间是50%,期望CPU被100%利用,套用公式:4 × 100% × 100% ÷ 50% = 8

例如4核CPU计算时间是10%,其它等待时间是90%,期望CPU被100%利用,套用公式:4 × 100% × 100% ÷ 10% = 40


2. ThreadPoolExecutor

2.1. 线程池状态

ThreadPoolExecutor 使用 int 的高3位来表示线程池状态,低29位表示线程数量。

状态高3位接收新任务处理队列任务说明
RUNNING111初始化状态和运行中状态
SHUTDOWN000不接收新任务,只处理队列中剩余的任务
STOP001中断正在执行的任务,抛弃队列中的任务
TIDYING010任务执行完毕,活动线程为0,即将终结
TERMINATED011线程池已终结

从数字上比较,TERMINATED > TIDYING > STOP > SHUTDOWN > RUNNING。

用一个原子变量 ctl 来存储是为了能在一次 CAS 操作中,既能修改状态,也能修改数量。

2.2. 基本原理

2.2.1. 构造方法

public ThreadPoolExecutor(
    int corePoolSize,			// 核心线程数(不会被销毁的线程数)
    int maximumPoolSize,		// 最大线程数(核心线程数 + 非核心线程数)
    long keepAliveTime,			// 非核心线程的生存时间
    TimeUnit unit,			// 非核心线程的生存时间单位
    BlockingQueue<Runnable> workQueue,	// 工作队列(需要自己设置队列的容量)
    ThreadFactory threadFactory,	// 线程工厂(可以为线程起个名字)
    RejectedExecutionHandler handler	// 饱和拒绝策略
)
复制代码

2.2.2. 组成部分

  • 核心线程: 提交新任务时,首先检查已创建的核心线程数:
    • 如果数量未达到核心线程数,则新建一个核心线程,并且将这个任务交由这个核心线程执行。
    • 如果数量已达到核心线程数,则不会新建核心线程,而会将这个任务放入工作队列中。
  • 工作队列: 当核心线程执行完一个任务后,会去工作队列中拉取一个新任务继续执行。一般是一个线程安全的有界阻塞队列。
  • 非核心线程: 如果继续提交新任务,且工作队列中的任务数量已达到队列的最大容量,当前线程数没有超过最大线程数,则会新建一个非核心线程执行这个任务。(核心线程和非核心线程本质上它们没有什么区别)
  • 线程生存时间: 非核心线程空闲之后,超过这个时间还没有任务执行,该线程结束。
  • 饱和拒绝策略: 当工作队列已满,线程数也达到最大线程数时,线程池会根据饱和策略来执行后续操作。

2.2.3. 工作流程

【类比理解】

有一家银行(线程池),有两个固定窗口(核心线程数为2),3位工作人员(最大线程数为3),等候座位(任务队列),一个规则《超出银行最大接待能力处理办法》(饱和拒绝策略):

  • A客户(任务A)去银行(线程池)办理业务,但银行刚开始营业,窗口服务员还未就位(相当于线程池中初始线程数量为0),于是经理(线程池管理者)就安排1号工作人员(创建核心线程1去执行任务)接待A客户。
  • 在A客户业务还没办完时,B客户(任务B)又来了,于是经理(线程池管理者)就安排2号工作人员(创建核心线程2去执行任务)接待B客户。
  • 在A、B客户都没有办完业务的情况下,C客户(任务C)来了,于是经理(线程池管理者)就安排C客户先坐到等候座位上,并告知他:如果1、2号工作人员空出,C客户就可以前去办理业务。
  • 此时D客户(任务D)又来了,(两个窗口都在忙,等候座位也满了)于是经理(线程池管理者)赶紧安排3号工作人员(创建非核心线程3去临时执行任务D)在大堂站着给D客户办理业务。
  • 假如前面的业务都没有结束的时候E客户(任务E)又来了,此时2位窗口工作人员,和1位临时工作人员都在忙,等候座位也满了,于是经理只能按《超出银行最大接待能力处理办法》(饱和处理机制)拒接接待E客户。
  • 最后,进来办业务的人少了,等候座位也空了,3号工作人员空闲时间也超过了1个小时(线程生存时间),经理就会让这部分空闲的员工人下班(销毁非核心线程),但是为了保证银行正常工作(有一个 allowCoreThreadTimeout 变量控制是否允许销毁核心线程,默认 false),即使窗口工作人员闲着也不得提前下班,所以1、2号工作人员继续等待新客户(池内保持核心线程数量);

2.3. 拒绝策略

2.3.1. JDK 的4种策略

  • AbortPolicy:不处理任务,且抛出 RejectedExecutionException 异常。【默认策略】
  • CallerRunsPolicy:不处理任务,交给调用者所在的线程(如主线程)来执行任务。
  • DiscardPolicy:不处理任务,且不抛出任何异常。
  • DiscardOldestPolicy:LRU 策略,丢弃队列里最近最久不使用的一个任务,并执行当前任务。

2.3.2. 其他策略

  • Dubbo 的实现,在抛出 RejectedExecutionException 异常之前会记录日志,并 dump 线程栈信息,方便定位问题。
  • Netty 的实现,是创建一个新线程来执行任务。
  • ActiveMQ 的实现,带超时等待(60s) 尝试放入队列,类似我们之前自定义的拒绝策略。
  • PinPoint 的实现,它使用了一个拒绝策略链,会逐一尝试策略链中每种拒绝策略。

2.4. Executors 工厂

2.4.1. newFixedThreadPool()

创建一个固定线程数的线程池。适用于任务量小且任务相对耗时的场景。

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}
复制代码

【特点】

  • 核心线程数 = 最大线程数(没有非核心线程),无超时时间。
  • 阻塞队列是无界的,可以放任意数量的任务。

2.4.2. newCachedThreadPool()

创建一个无限线程数的线程池。适用于任务量大且任务相对轻松的场景。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
复制代码

【特点】

  • 核心线程数是0,最大线程数是 Integer.MAX_ VALUE,非核心线程的空闲生存时间是60s,意味着
    • 全部都是非核心线程(60s 后可以回收)。
    • 非核心线程可以无限创建。
  • 队列采用了 SynchronousQueue 实现,特点是没有容量,没有线程来取是放不进去的(一手交钱、一手交货)。

2.4.3. newSingleThreadExecutor()

创建一个单线程的线程池。适用于任务串行且任务相对轻松的场景。

public static ExecutorService newSingleThreadExecutor() {
    // 装饰器模式,防止外部直接调用ThreadPoolExecutor的方法
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
复制代码

【特点】

  • 线程数固定为1,任务数多于1时,会放入无界队列排队。任务执行完毕,这唯一的线程也不会被释放。

【区别】

  • 自己创建一个单线程串行执行任务,如果任务执行失败而终止那么没有任何补救措施;而线程池还会新建一个线程,保证池的正常工作。
  • Executors.newSingleThreadExecutor() 线程个数始终为1且不能修改,FinalizableDelegatedExecutorService 应用的是装饰器模式,只对外暴露了ExecutorService 接口,因此不能调用 ThreadPoolExecutor 中特有的方法。
  • Executors.newFixedThreadPool(1) 初始时为1,以后还可以修改。对外暴露的是 ThreadPoolExecutor 对象,可以强转后调用 setCorePoolSize 等方法进行修改。

2.5. 提交任务

2.5.1. execute()

提交一个不需要返回值的任务,所以无法判断任务是否被线程池执行成功。

ExecutorService threadPool = Executors.newFixedThreadPool(2);
threadPool.execute(() -> System.out.println("执行任务"));
复制代码

【源码分析】

public void execute(Runnable command) {
    if (command == null) throw new NullPointerException();
    int c = ctl.get();
    // workerCountOf(c)会获取当前正在运行的worker数量
    if (workerCountOf(c) < corePoolSize) {
        // 如果workerCount小于corePoolSize,就创建一个worker然后直接执行该任务
        if (addWorker(command, true)) return;
        c = ctl.get();
    }
    // isRunning(c)是判断线程池是否在运行中,如果线程池被关闭了就不会再接受任务
    // workQueue.offer(command)是将任务加入到队列中
    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);
    }
    // 如果加入队列失败,就尝试直接创建worker来执行任务
    else if (!addWorker(command, false))
        // 如果创建worker失败,就执行拒绝策略
        reject(command);
}
复制代码

2.5.2. submit()

提交一个需要返回值的任务。

ExecutorService threadPool = Executors.newFixedThreadPool(2);
Future<String> future = threadPool.submit(() -> {
    System.out.println("执行任务");
    return "OK";
});
try {
    Thread.sleep(100);
    System.out.println(future.get());	// OK
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}
复制代码

2.5.3. InvokeAll()

批量提交需要返回值的任务。

ExecutorService threadPool = Executors.newFixedThreadPool(2);
List<Future<String>> futures = threadPool.invokeAll(Arrays.asList(
        () -> {
            System.out.println("执行任务1");
            return "OK1";
        },
        () -> {
            System.out.println("执行任务2");
            return "OK2";
        }
));
Thread.sleep(100);
for (Future<String> future : futures) {
    try {
        System.out.println(future.get());
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
复制代码

2.5.4. InvokeAny()

批量提交需要返回值的任务。哪个任务先成功执行完毕,返回此任务执行结果,然后取消其它任务。

ExecutorService threadPool = Executors.newFixedThreadPool(2);
String future = threadPool.invokeAny(Arrays.asList(
        () -> {
            System.out.println("执行任务1");
            return "OK1";
        },
        () -> {
            System.out.println("执行任务2");
            return "OK2";
        }
));
Thread.sleep(100);
System.out.println(future);		// OK1 或者 OK2
复制代码

2.6. 关闭线程池

2.6.1. shutdown()

不会立即终止线程池,而是要等所有工作队列中的任务都执行完后才终止,但也不会再接受新的任务。

ExecutorService threadPool = Executors.newFixedThreadPool(2);
threadPool.shutdown();
复制代码

【源码分析】

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        // 把线程池的状态置为 SHUTDOWN
        advanceRunState(SHUTDOWN);
        // 中断空闲线程
        interruptIdleWorkers();
        // ScheduledThreadPoolExecutor用来hook的地方
        onShutdown();
    } finally {
        mainLock.unlock();
    }
    // 尝试终结线程池(没有运行的线程可以立刻终结,如果还有运行的线程也不会等)
    tryTerminate();
}
复制代码

2.6.2. shutdownNow()

先将线程池的状态设置成 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表。

ExecutorService threadPool = Executors.newFixedThreadPool(2);
threadPool.shutdownNow();
复制代码

【源码分析】

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        // 把线程池的状态置为 STOP
        advanceRunState(STOP);
        // 中断全部线程
        interruptWorkers();
        // 获取队列中的剩余任务
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    // 尝试终结线程池(没有运行的线程,因此立刻终结)
    tryTerminate();
    return tasks;
}
复制代码

2.7. 任务调度线程池

2.7.1. Timer

Timer 简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,前一个任务的延迟或异常都将会影响到之后的任务。

public static void main(String[] args) {
    Timer timer = new Timer();
    TimerTask task1 = new TimerTask() {
        @Override
        public void run() {
            Log.println("task1");
            Thread.sleep(1000);
        }
    };
    TimerTask task2 = new TimerTask() {
        @Override
        public void run() {
            Log.println("task2");
            Thread.sleep(1000);
        }
    };
    timer.schedule(task1, 0);
    timer.schedule(task2, 0);	// 任务2要等待任务1执行完毕才能执行
}
复制代码

2.7.2. ScheduledThreadPoolExecutor

  • schedule():添加延时任务。
  • scheduleAtFixedRate():添加固定速率的循环延时任务(上一个任务未结束,当前任务也是按时执行)。
  • scheduleWithFixedDelay():添加固定延时的循环延时任务(等待上一个任务结束,再等待延时时间后才执行当前任务)。

2.8. 线程池的异常处理

2.8.1. try/catch

public static void main(String[] args) {
    ExecutorService threadPool = Executors.newFixedThreadPool(1);
    threadPool.submit(() -> {
        Log.println("running...");
        // 自行捕获异常
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}
复制代码

15:32:08:572: running...

java.lang.ArithmeticException: / by zero

2.8.2. FutureTask

public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService threadPool = Executors.newFixedThreadPool(1);
    Future<String> future = threadPool.submit(() -> {
        Log.println("running...");
        int i = 1 / 0;
        return "OK";
    });
    // 如果FutureTask执行成功,则get()获取到返回值,如果执行失败,则抛出异常
    Log.println(future.get());
}
复制代码

15:35:12:300: running...

Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

需要资料的小伙伴,点赞加收藏,关注我之后添加小助理vx:bjmsb0606006 即可获取免费下载方式

java多线程之多线程的三大特性 多线程的三大特性:原子性、可见性、有序性 1.什么是原子性 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 一个很经典的例子就是银行账户转账问题: 比如从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。这2个操作必须要具备原子性才能保证不出现一些意外的问题。 我们操作数据也是如此,比 阅读详情

相关推荐

告别黑窗口!用VSCode+Native Debug调试C/C++程序,比GDB命令行舒服多了

本文介绍了如何使用VSCode配合Native Debug扩展来调试C/C++程序,替代传统的GDB命令行方式。通过可视化调试环境,开发者可以更高效地管理断点、查看变量和调用栈,大幅提升调试效率。文章详细讲解了环境配置、核心调试功能及高级技巧,帮助开发者快速上手这一现代调试工具。

weixin_26833139的博客 224

Java 线程池详解

线程池是一组已经初始化并等待执行任务的线程集合。通过使用线程池,我们可以避免频繁地创建和销毁线程,从而节省资源和减少系统开销。线程池的核心思想是通过复用线程来提高性能。

qq_41591215的博客 1万+

5.17华为OD机试真题 新系统 - 输出二叉树后序遍历结果 (Java/Py/C/C++/Js/Go)

5.17华为OD机试真题 新系统 - 输出二叉树后序遍历结果 (Java/Py/C/C++/Js/Go)

算法大师! 443

java四大线程池特点和源码分析

一、线程池的好处 (1)降低资源消耗。通过重复利用已创建的线程降低线程创建、销毁线程造成的消耗。 (2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。 (3)提高线程的可管理性。线程是稀缺资源,如果入限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。 二、线程池的核心参数 new ThreadPoolExecutor(int co...

zfx2013的博客 277

用银行办业务类比JS的执行机制

6、postMessage、MessageChannel和BroadcastChannel的回调:它们通常会涉及到回调和异步处理,比如使用send()和receive()方法,它们会触发相应的回调,这些回调会被浏览器放入微任务队列中等待执行,会间接影响任务队列的调度。在异步任务的事件队列中,又分为宏任务和微任务,宏任务是普通客户,微任务是vip客户,他们分别站成两个不同的队,分为宏任务队列和微任务队列。同步业务遵循后来先办的原则,因为每个新来的同步任务客户会把文件放在最上面,工作人员会先办理后来的。

博客of me 656

JAVA线程池详解

最全java线程池详解,看这一篇就够了...

ZHANGLIZENG的博客 1万+

Java线程()线程池

上一篇:Java线程() 下一篇:Java线程() 自JDK5之后,Java推出了一个并发包,java.util.concurrent,在Java开发中,我们接触到了好多池的技术,String类的对象池、Integer的共享池、连接数据库的连接池、Struts1.3的对象池等等,池的最终目的都是节约资源,以更小的开销做更多...

weixin_30338481的博客 251

Java进阶笔记线程池类比银行业务理解

文章目录1. Java 线程池1.1. 线程池特点1.2. Java 中的线程池类1.3. 线程池的最佳容量2. ThreadPoolExecutor2.1. 线程池状态2.2. 基本原理2.2.1. 构造方法2.2.2. 组成部分2.2.3. 工作流程2.3. 拒绝策略2.3.1. JDK 的4种策略2.3.2. 其他策略2.4. Executors 工厂2.4.1. newFixedThreadPool()2.4.2. newCachedThreadPool()2.4.3. newSingleThre

Android学习笔记 617

java银行业务怎么样,害 其实银行就是一个Java线程池

银行就是一个线程池image-20201126113618828银行实际上就是一个Java线程池。一次周末去银行办业务,人多排号,排的久了突然发现银行实际上和Java线程池如此类似,可以说一模一样。于是我就展开了联想。银行是个线程池周末,银行七个窗口只来了两个值班的员工,那么这两个员工我们就叫做核心员工数那天由于不知道什么原因,来银行办业务的人特别多,两个员工很快就忙不过来了,那么新来的人怎么办...

weixin_35725138的博客 1063

java线程池学习笔记

Callable<> 接口 FutureTask是实现了runable的子接口的,而他的构造可以接收callable,这样new Thread就可以传这个callable了 线程池 线程池优势 线程池常用的几个方式 这个不是重点,知道即可,加上java8新出大多一共5种 带调度的-Executors.newScheduledThreadPool() Executors.new...

weixin_43769566的博客 317

java笔记-银行业务调度系统

模拟实现银行业务调度系统逻辑,需求如下: 1.银行内有l

cs.Ing 877

黑马程序Java培训、Android培训_银行业务调度系统笔记

银行业务调度系统一、学习心得:第一点,和交通灯系统一样,银行业务调度系统也必须用面相对象的思想来设计,不然会很繁琐。所以,必须在平时的学习中重视面向对象设计的练习和掌握。第二点,要设计这个银行业务系统,就要将这个银行的业务搞明白,细节之处不能忽视,比如这几个问题的解决,这么多业务

程序员的人生 824

通俗语言介绍Java 线程池

Java 线程池 这玩意前几天面试被问到了,和数据库连接池搞混了,没答好,随手mark一下吧。 线程池核心类:ThreadPoolExecutor 主要介绍它的核心构造方法 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFac

LIUZEYU12A 390

黑马程序java提高——张孝祥银行业务调度系统

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ---------------------- 银行业务调度系统 一:银行业务调度系统的项目需求分析: 模拟实现银行业务调度系统逻辑,具体需求如下:  Ø 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为V

u012562441的专栏 915

十五. 线程池

线程池的优势: 线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。 它的主要特点为:线程复用;控制最大并发数;管理线程。 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗。 第二:提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。 第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低

weixin_42480780的博客 135

java 线程池 优点_Java多线程系列-线程池的优点和方法

new Thread的弊端如下:a. 每次new Thread新建对象性能差。b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。c. 缺乏更多功能,如定时执行、定期执行、线程中断。相比new Thread,Java提供的四种线程池的好处在于:a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。b. 可有效控制最大并发线程数,提高系统资源的使用率,...

weixin_32927369的博客 763

Java 类库提供了几种线程池? 分别有什么特点

线程池 Java语言虽然内置了多线程支持,启动一个新线程非常方便,但是,创建线程需要操作系统资源(线程资源,栈空间等),频繁创建和销毁大量线程需要消耗大量时间 如果可以复用一组线程: 在没有任务时线程处于空闲状态,当请求到来:线程池给这个请求分配一个空闲的线程,任务完成后回到线程池中等待下次任务(而不是销毁)。这样就实现了线程的重用。 为每个请求都开一个新的线程虽然理论上是可以的,但是会有缺点: 线程生命周期的开销非常高。每个线程都有自己的生命周期,创建和销毁线程所花费的时间和资源可能比处理客户端的任务

@另维 577

Java多线程系列-线程池的优点和方法

new Thread的弊端如下: a. 每次new Thread新建对象性能差。 b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。 c. 缺乏更多功能,如定时执行、定期执行、线程中断。 相比new Thread,Java提供的四种线程池的好处在于: a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。 b. 可有效控制最

FeelTouch Labs 2713

java线程池有什么作用_java_以实例简介Java线程池的工作特点,什么原因使我们不得不使用线 - phpStudy...

以实例简介Java线程池的工作特点什么原因使我们不得不使用线程池?个人认为主要原因是:短时间内需要处理的任务数量很多使用线程池的好处:1.减少在创建和销毁线程上所花的时间以及系统资源的开销2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以下是Java自带的几种线程池:1、newFixedThreadPool 创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程...

weixin_34539644的博客 226

java线程池详解

java线程池详解一、线程池存在的意义线程池的优点二、线程池工作原理三、线程池的优缺点及使用场景四、常用线程池类型五、合理的配置线程池的大小 我们要了解线程池,首先要知道线程池产生的原因即线程池存在的意义,然后再剖析其工作原理,以及如何合理使用线程,这样我们才会对线程池有个较为深刻的认知。本文只是线程池认知概览,更为深入的机制还需要大家一起探究 一、线程池存在的意义 我们常见的创建线程的方法,一种...

fxd873的博客 3962

SIMATIC WinCC和三菱FX3U、Q 系列PLC以太网通讯的组态方法步骤.rar

SIMATIC WinCC和三菱FX3U、Q 系列PLC以太网通讯的组态方法步骤

上一篇: 浅谈Java的网络编程,带你领略Java的世界
下一篇: 全网最容易理解的spring dispatcher请求流程解析,看不懂你打我
Fightevery
博客等级 码龄5年 20粉丝 223原创
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值