Java线程池


线程池就是多个可执行任务的线程的集合,在执行大量线程任务的时候,由于线程池里的线程可以复用,因而可以减少新建和调用线程的次数,从而提高性能。

此外,使用线程池让你无需管理线程的生命周期,它让你在利用线程优势的同时,只需专注于任务的执行,而无需关心线程机制。



1. 创建线程池常用的方法

介绍几个常用的创建线程池的方法(使用 Executors类的构造方法来构建):

  • public static ExecutorService Executors.newSingleThreadExecutor() :
    创建一个单线程的Executor来操作任务队列,队列中的任务将依次执行,队列中一次只有一个任务处于活动状态。如果该线程在关闭之前由于执行任务出错而被终止,在执行后续任务的时候将创建一个新的线程来替代该线程。

  • public static ExecutorService Executors.newSingleThreadExecutor(ThreadFactory threadFactory)
    和上面的方法效果一样,不同之处在于它支持使用自定义创建的线程。

  • public static ExecutorService Executors.newFixedThreadPool(int nThreads)
    创建一个拥有固定个线程数量的线程池。在任意时刻,最多有nThreads个线程处于活动状态来处理任务。如果任务数量多于nThreads个或者当所有线程都处于活动状态时又提交了新的任务,那么多余的任务将处于等待状态直到某个线程可以使用。如果任一线程在关闭之前由于执行任务出错而被终止,在执行后续任务的时候将创建一个新的线程来替代该线程。线程池中的所有线程直到被明确地关闭(调用了ExecutorService.shutdown())之前都将存在。

  • public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
    和上面的方法类似

  • public static ExecutorService newCachedThreadPool()
    创建一个线程池,线程池中线程的数量根据任务需求而定。如果当前有新的任务要执行而线程池中又没有可用的线程,那么就会创建新的线程添加到线程池中并用来执行任务。如果当前有可用线程,就会复用已存在的线程来执行任务。任意一个线程如果60秒之内没有执行任务,就会被自动移除,因此处于长时间(超过60秒)待机状态的线程池不会占用任何资源。对于需要执行大量短周期异步任务的程序,使用这种线程池能显著提高性能。

  • public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
    和上面的方法类似

如果需要创建与上述相似,但细节上有所差异的线程池,可以考虑使用 ThreadPoolExecutor 类的构造方法。
如果需要创建可以执行定时或者延迟任务的线程池,可以考虑使用 ScheduledThreadPoolExecutor 类的构造方法



2. 举例比较

下面来举几个例子比较一下不同类型线程池的区别。

先写一个任务类,在任务开始和结束时分别打印任务名称和所在线程:

public class MyRunnable implements Runnable {    
       private String taskName;    
       public MyRunnable(String name){        
               this.taskName = name;    
       }    
       
       @Override    
       public void run() {        
               Printer.print(taskName + " start; Current thread is " + Thread.currentThread().getName());        
               try {            
                       Thread.sleep(1000);        
               }catch (Exception e){}        
               Printer.print(taskName + " finished.");    
        }
}

创建6个任务,同时交给线程池处理

private static void testThreadPool(){        
        List<Runnable> tasks = new ArrayList<>();        
        for(int i = 0; i < 6; i++){            
                Runnable task = new MyRunnable("task" + i);            
                tasks.add(task);        
        }        
        ExecutorService threadPool = Executors.newSingleThreadExecutor();   //case 1
 //    ExecutorService threadPool = Executors.newFixedThreadPool(4);     //case 2
 //    ExecutorService threadPool = Executors.newCachedThreadPool();     //case 3        
        for(Runnable runnable : tasks){            
                threadPool.execute(runnable);        
        }    
}

我们尝试用以上三种不同的方式创建线程池,来执行这6个任务,看输出结果有什么区别:

case 1:

task0 start; Current thread is pool-1-thread-1
task0 finished.
task1 start; Current thread is pool-1-thread-1
task1 finished.
task2 start; Current thread is pool-1-thread-1
task2 finished.
task3 start; Current thread is pool-1-thread-1
task3 finished.
task4 start; Current thread is pool-1-thread-1
task4 finished.
task5 start; Current thread is pool-1-thread-1
task5 finished.

case1 中始终只有一个线程,6个任务一个接一个执行完毕。

case 2:

task0 start; Current thread is pool-1-thread-1
task1 start; Current thread is pool-1-thread-2
task2 start; Current thread is pool-1-thread-3
task3 start; Current thread is pool-1-thread-4
task0 finished.
task2 finished.
task1 finished.
task5 start; Current thread is pool-1-thread-3
task4 start; Current thread is pool-1-thread-1
task3 finished.
task5 finished.
task4 finished.

case2 的线程池中有4个线程,先同时执行了4个任务,执行完任务的线程接着执行剩余的任务。

case 3:

task1 start; Current thread is pool-1-thread-2
task4 start; Current thread is pool-1-thread-5
task0 start; Current thread is pool-1-thread-1
task3 start; Current thread is pool-1-thread-4
task2 start; Current thread is pool-1-thread-3
task5 start; Current thread is pool-1-thread-6
task5 finished.
task1 finished.
task0 finished.
task2 finished.
task4 finished.
task3 finished.

case3 由于一次传入了6个任务,线程池也相应创建了6个线程,同时开始执行任务。


补充一个类 java.lang.ThreadGroup,任意一个线程都可以通过 Thread.getThreadGroup() 方法获取到它所在的线程组,在初始化Thread类的时候可以为其指定ThreadGroup。使用线程组可以方便地对一组线程进行有限的操作。线程组与线程池无关,这里只是提及一下,不做更多介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值