论述题 8.  请简要介绍对线程池的理解。
【正确答案】在Java语言中,可以通过new Thread的方法来创建一个新的线程执行任务,但是线程的创建是非常耗时的,而且创建出来的新的线程都是各自运行、缺乏统一的管理,这样做的后果是可能导致创建过多的线程从而过度消耗系统的资源,最终导致性能急剧下降,线程池的引入就是为了解决这些问题。
   当使用线程池控制线程数量时,其他线程排队等候,当一个任务执行完毕后,再从队列中取最前面的任务开始执行。如果队列中没有等待进程,那么线程池中的这一资源会处于等待状态。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了,否则,进入等待队列。
   一方面,线程池中的线程可以被所有工作线程重复利用,一个线程可以用来执行多个任务,这样就减少了线程创建的次数;另一方面,它也可以限制线程的个数,从而不会导致创建过多的线程进而导致性能下降。当需要执行任务的个数大于线程池中线程的个数时,线程池会把这些任务放到队列中,一旦有任务运行结束,就会有空闲的线程,此时线程池就会从队列里取出任务继续执行。
   目前Java语言主要提供了如下4个线程池的实现类:
   1)newSingleThreadExecutor:创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,也就是相当于单线程串行执行所有任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。使用方法如下:
   import java.util.concurrent.ExecutorService;
   import java.util.concurrent.Executors;
   class MyThread extends Thread{
   public void run(){
   System.out.println(Thread.currentThread().getId()+"run");
   }
   }
   public class TestSingleThreadExecutor{
   public static void main(String[]args){
   ExecutorService pool=Executors.newSingleThreadExecutor();
   //将线程放入池中进行执行
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   //关闭线程池
   pool.shutdown();
   }
   }
   程序的运行结果为:
   15 run
   15 run
   15 run
   15 run
   2)newFixedThreadPool:创建一个定长线程池,可控制线程的最大并发数,超出的线程会在队列中等待。使用这个线程池的时候,必须根据实际情况估算出线程的数量。
   示例代码如下:
   import java.util.concurrent.ExecutorService;
   import java.util.concurrent.Executors;
   class MyThread extends Thread{
   public void run(){
   System.out.println(Thread.currentThread().getId()+"run");
   }
   }
   public class TestNewFixedThreadPool{
   public static void main(String[]args){
   ExecutorService pool=Executors.newFixedThreadPool(2);
   //将线程放入池中进行执行
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   //关闭线程池
   pool.shutdown();
   }
   }
   程序的运行结果为:
   15 run
   15 run
   15 run
   17 run
   3)newCachedThreadPooh创建一个可缓存线程池,如果线程池的长度超过处理需要,可灵活回收空闲线程,如果不可回收,则新建线程。此线程池不会对线程池的大小做限制,线程池的大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。使用这种方式需要在代码运行的过程中通过控制并发任务的数量来控制线程的数量。示例代码如下:
   import java.util.concurrent ExecutorService;
   import java.util.concurrent.Executors;
   class MyThread extends Thread{
   public void run(){
   System.out.println(Thread.currentThread().getId()+"run");
   }
   }
   public class TestNewCachedThreadPool{
   public static void main(String[]args){
   ExecutorService pool=Executors.newCachedThreadPool();
   //将线程放入池中进行执行
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   pool.execute(new MyThread());
   //关闭线程池
   pool.shutdown();
   }
   }
   程序的运行结果为:
   15 run
   17 run
   19 run
   21 run
   4)newScheduledThreadPool:创建一个定长线程池。此线程池支持定时以及周期性执行任务的需求。
   示例代码如下:
   import java.util.concurrent.ScheduledThreadPoolExecutor;
   import java.util.concurrent.TimeUnit;
   class MyThread extends Thread{
   public voidrun(){
   System.out.println(Thread.currentThread().getId()+"timestamp:"+System.currentTlmeMillis());
   }
   }
   public class TestScheduledThreadPoolExecutor{
   public static void main(String[]args){
   ScheduledThreadPoolExecutor exec=new ScheduledThreadPoolExecutor(2);
   //每隔一段时间执行一次
   exec.scheduleAtFixedRate(new MyThread(),0,3000,TimeUnit.MILLISECONDS);
   exec.scheduleAtFixedRate(new MyThread0,0,2000,TimeUnit.MILLISECONDS);
   }
   }
   程序的运行结果为:
   15 timestamp:1443421326105
   17 timestamp:1443421326105
   15 timestamp:1443421328105
   17 timestamp:1443421329105
【答案解析】