zoukankan      html  css  js  c++  java
  • Java多线程系列——线程池简介

    什么是线程池?

    为了避免系统频繁地创建和销毁线程,我们可以让创建的线程进行复用。
    用线程时从线程池中获取,用完以后不销毁线程,而是归还给线程池。

    JDK 对线程池的支持

    为了更好的控制多线程,JDK 提供了一套线程池框架,结构如下图所示

    它们都在 java.util.concurrent 包中。

    • Executor 用来执行任务,它提供了 execute() 方法来执行 Runnable 任务;
    • ThreadPoolExecutor 表示一个线程池;
    • Executors 它是一个静态工厂工厂类,通过它可以取得一个拥有特定功能的线程池;

    不同特性的线程池

    1. newFixedThreadPool():返回固定数量的线程池。线程池中的数量始终不变。当有新任务提交时,线程池中若有空闲线程,则立即执行。若没有则放入任务队列中,等待有空闲线程时,处理任务队列中的任务。
    2. newSingleThreadPool():返回只有一个线程的线程池。若有多余一个任务被提交,则放入任务队列中,等待有空闲线程时,按先入先出的顺序执行队列中的任务。
    3. newCachedThreadPool():返回一个可根据实际情况调整线程数量的线程池。这个方法创建出来的线程池可以被无限扩展,并且当需求降低时会自动收缩。
    4. newSingleThreadScheduledExecutor():返回一个 ScheduledExecutorService 对象,线程池大小为 1。ScheduledExecutorService 接口在 ExecutorService 接口之上扩展了在给定时间执行某任务的功能,在某个固定时间延迟之后,或周期性执行某个任务。
    5. newScheduledThreadPool():返回一个 ScheduledExecutorService 对象,并可指定线程数量。
    6. ScheduledExecutorService 并不一定会立即安排执行任务,而是起到了计划任务的作用。
    7. 它主要有一下三个方法:
      1. schedule():会在给定的时间,对任务进行一次调度
      2. scheduleAtFixedRate():创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期
      3. scheduleWithFixedDelay():创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟

    示例

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    /**
     * Created by zhengbin on 2017/10/24
     */
    public class ExecutorServiceTest {
        private static class Task implements Runnable {
        public void run() {
                System.out.println(System.currentTimeMillis() + ":Thread ID:" + Thread.currentThread().getId());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) {
            Task t = new Task();
            ExecutorService executorService = Executors.newFixedThreadPool(5);
            for (int i = 0; i < 10;i++) {
                executorService.execute(t);
            }
            executorService.shutdown();
        }
    }

    运行结果

    1509258535474:Thread ID:11
    1509258535474:Thread ID:12
    1509258535475:Thread ID:14
    1509258535475:Thread ID:15
    1509258535475:Thread ID:13
    1509258536475:Thread ID:15
    1509258536475:Thread ID:11
    1509258536475:Thread ID:12
    1509258536475:Thread ID:14
    1509258536475:Thread ID:13

    结果说明

    主线程创建了一个固定大小的线程池,线程池的容量是 5。

    运行结果输出了运行的时间戳,可以看到,前 5 个任务执行的时间戳与后 5 个任务的时间戳相差了 1000 毫秒。

    这说明在这 10 个任务中,是分成 2 批次执行的。这也完全符合一个只有 5 个线程的线程池的行为。

    当把线程池改为 newCachedThreadPool() 时,就会将 10 个任务同时执行。

  • 相关阅读:
    启用oracle 11g自己主动收集统计信息
    在java中,怎样跳出当前的多重循环?
    从编程的角度理解gradle脚本﹘﹘Android Studio脚本构建和编程[魅族Degao]
    【SpringMVC架构】SpringMVC入门实例,解析工作原理(二)
    实现icon和文字垂直居中的两种方法-(vertical-align and line-height)
    android发送get请求时报错
    KeyEvent 键码值
    Android-黑科技-微信抢红包必备软件
    Delicious Apples (hdu 5303 贪心+枚举)
    vim 插件配置博客记录
  • 原文地址:https://www.cnblogs.com/zhengbin/p/7750077.html
Copyright © 2011-2022 走看看