并发库:简介与线程池的基本使用

Java 5 添加了一个新的包到Java平台,java.util.concurrent包(即多线程并发库)。这个包包含一系列能够让Java的并发编程变得更加简单轻松的类。

java.util.concurrent包还有两个子包

  • java.util.concurrent.atomic 包 (多线程的原子性操作提供的工具类)
  • java.util.concurrent.lock 包 (多线程的锁机制)

线程池

对于某个任务,如果我们创建很多个线程,都会有一个创建过程以及销毁过程,占用系统资源,这样就会大大地降低程序运行的效率。为了能够让一个线程用完之后不被销毁,而是被重复利用,就引入了一个技术:线程池。

使用线程池的好处

  • 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
  • 可以根据系统的承受能力,限制和调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约 1MB 内存,线程开的越多,消耗的内存也就越大,最后死机)

底层原理

线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。

三种线程池

java.util.concurrent.Executors类是一个线程池的工厂类,用来生成线程池。该类中提供了生成多种线程池的静态方法。

ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4);

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();

  • newSingleThreadExecutor:创建一个单线程的线程池,并且如果前一个线程死了,就会再自动创建一个新的线程。
  • newFixedThreadPool:创建固定大小的线程池,每次提交一个任务就使用一个线程,直到线程达到线程池的最大大小。
  • newCachedThreadPool:创建一个可缓存的线程池,此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说 JVM)能够创建的最大线程大小。

线程池的使用

以Executors.newFixedThreadPool()为例来讲解,用来生成一个可反复使用的指定线程数的线程池:

参数是线程池中要包含的线程数。

返回值是一个ExecutorService接口对象,该接口的顶层接口Executor中有一个execute方法,用来执行一个线程任务,并且没有任何返回值

使用步骤如下:

  1. 使用线程池的生产类Executors中的静态方法newFixedThreadPool,来创建一个指定线程数的线程池
  2. 使用execute()方法,传递线程任务去执行
  3. 可以选择调用shutdown方法销毁线程,但是一般不推荐

使用示例:

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("扔一个任务给线程池");
        }
    });
}

注意:线程池会一直开启,使用完了线程,会自动把线程归还给线程池,线程可以继续使用。所以可能会出现同一个线程执行了多次任务的情况。

关闭线程池

当所有的任务都执行完了,可以选择执行shutdown()方法来销毁线程池。

shutdown 只是将空闲的线程 interrupt() 了,shutdown()之前提交的任务可以继续执行直到结束。

如果想销毁所有线程,可以使用shutdownNow()方法,大部分线程将立刻被中断。之所以是大部分,而不是全部 ,是因为该方法能力有限。

发布了70 篇原创文章 · 获赞 1 · 访问量 2273

猜你喜欢

转载自blog.csdn.net/caozp913/article/details/103464865