Java多线程-线程池

本文详细介绍了Java中的线程池机制,包括Executor框架、ExecutorService接口和Executors工厂类。讲解了四种线程池类型:缓存线程池、定长线程池、单线程线程池和周期性任务线程池的工作原理及应用场景。此外,还提到了自定义线程池的创建方法,强调了线程池在资源管理和性能优化上的重要性。
摘要由CSDN通过智能技术生成

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程 就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。

线程池的好处:

  • 降低资源消耗

  • 提高响应速度

  • 提高线程的可管理性。

1. Executor

Java 5中引入了Executor框架,其内部使用了线程池机制,它在java.util.cocurrent 包下

  • 通过Executor来启动线程比使用Thread的start方法更好,更易管理,效率更好(用线程池实现,节约开销)

  • Executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制。

  • 有助于避免this逃逸问题

    this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象

Executor 、 ExecutorService 、 Executors

ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口,ExecutorService 还提供用来控制线程池的方法

  • Executor 接口定义了 execute()方法用来接收一个Runnable接口的对象,而 ExecutorService 接口中的 submit()方法可以接受RunnableCallable接口的对象

  • Executor 中的 execute() 方法不返回任何结果,而 ExecutorService 中的 submit()方法可以通过一个Future对象返回运算结果

  • Executors 类提供工厂方法用来创建不同类型的线程池,以下为java中常见的四种线程池:

    • Executors.newCachedThreadPool() :缓存线程池(长度无限制,自动创建线程)

    • Executors.newFixedThreadPool() :定长线程池 (线程池已满时需要等待)

    • Executors.newSingleThreadExecutor() :单线程线程池(效果与定长线程池 创建时传入数值1效果一致)

    • Executors.newScheduledThreadPool():周期性任务定长线程池

2. 缓存线程池

定义:

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

执行流程:

  1. 判断线程池是否存在空闲线程

  2. 存在则使用

  3. 不存在则创建线程、并放入线程池, 然后使用

示例:

public class CachedThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        
        executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
    }
}

3. 定长线程池

定义:

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

执行流程:

  1. 判断线程池是否存在空闲线程

  2. 存在则使用

  3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用

  4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程

public class FixedThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
​
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        });
​
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        });
​
        executorService.execute(()->{
            try {
                Thread.sleep(1200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        });
    }
}

4. 单线程线程池

定义:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()) );
}

执行流程:

  1. 判断线程池中的那个唯一的线程是否空闲

  2. 空闲则使用

  3. 不空闲, 则等待池中的单个线程空闲后再使用

public class SingleThreadExecutorDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        });

        executorService.execute(()->{
            try {
                Thread.sleep(1400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        });
    }
}

5. 周期性任务定长线程池

定义:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    // super: ThreadPoolExecutor
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue() );
}

执行流程:

  1. 判断线程池是否存在空闲线程

  2. 存在则使用

  3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用

  4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程

public class ScheduledThreadPoolDemo {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);

        // 定时任务:(5秒后执行)
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }, 5, TimeUnit.SECONDS);

        // 周期任务 (5秒后开始执行,间隔2秒重复执行)
        scheduledExecutorService.scheduleAtFixedRate(()->{
            System.out.println(Thread.currentThread().getName());
        }, 5, 2, TimeUnit.SECONDS);
    }
}

方法定义:

public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);

参数说明:

  • Runnable command:runnable类型的任务

  • long delay:时长数字(延迟执行的时长)

  • long period:周期时长(每次执行的间隔时间)

  • TimeUnit unit:时长数字的单位

6. 自定义线程池

如果需要自定义线程池,可以用 ThreadPoolExecutor 类创建,它有多个构造方法来创建线程池

// 以此为例:
public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long keepAliveTime, 
                           TimeUnit unit, BlockingQueue<Runnable> workQueue)
  • corePoolSize:线程池中所保存的核心线程数,包括空闲线程

  • maximumPoolSize:池中允许的最大线程数

  • keepAliveTime:线程池中的空闲线程所能持续的最长时间

  • unit:持续时间的单位

  • workQueue:任务执行前保存任务的队列,仅保存由execute方法提交的Runnable任务

public class ThreadPoolExecutorDemo {
    public static void main(String[] args) {
        //创建等待队列
        ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10);
        //创建线程池,池中保存的线程数为3,允许的最大线程数为5
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3, 5, 50, TimeUnit.MILLISECONDS, queue);
​
        poolExecutor.execute(()->{
            System.out.println(Thread.currentThread().getName());
        });
​
        // 关闭线程池
        poolExecutor.shutdown();
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值