• Java并发编程——线程池初步


    概述:

      线程池机制是事先创建一些线程等待服务端程序的调用,这些线程保存在一个数组结构中,称为“线程池”。当服务器有任务执行时,就从线程池中取出一个线程并给其分配任务,当线程任务执行完成后,再被放回线程池中。


    优点:

      1. 由于在任务到达之前,线程已经存在,所以这里为系统消除了线程创建的资源和时间的开销。可以立即为请求服务,使程序响应更快。

      2. 通过适当地调节线程池中的线程数目,就强制使一些新到的任务处于等待状态,可以防止资源不足。


    参考:

    http://www.cnblogs.com/dolphin0520/p/3932921.html

    《Java语言程序设计》——清华大学出版社


    示例及分析:

    MyTask.java

    public class MyTask implements Runnable {
    
    	private int taskNum;
    
    	public MyTask(int num) {
    		this.taskNum = num;
    	}
    
    	@Override
    	public void run() {
    		System.out.println("正在执行task " + taskNum);
    
    		try {
    			Thread.currentThread().sleep(3000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    
    		System.out.println("task " + taskNum + "执行完毕");
    	}
    
    }
    上面的程序很简单,就只是去打印一些简单的信息。


    Executor.java

    public class Executor {
    
    	public static void main(String[] args) {
    		ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5));
    
    		for (int i = 0; i < 15; i++) {
    			MyTask myTask = new MyTask(i);
    			if (!executor.isShutdown()) {
    				executor.execute(myTask);
    			}
    			
    			printExecutor(executor);
    		}
    		
    		executor.shutdown();
    	}
    	
    	private static void printExecutor(ThreadPoolExecutor executor) {
    		System.out.println("线程池中线程数目:" + executor.getPoolSize()
    				+ ",队列中等待执行的任务数目:" + executor.getQueue().size()
    				+ ",已执行完别的任务数目:" + executor.getCompletedTaskCount());
    	}
    }


    上面用到了java为我们提供的类ThreadPoolExecutor,这是一个很好的类。上面用到创建实例时用到的构造器如下:

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }


    它包含了下面这只个参数:

      int corePoolSize:线程池中线程数
      int maximumPoolSize:线程池中最大的线程数
      long keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止
      TimeUnit unit:参数keepAliveTime的时间单位,在TimeUnit类中有7种静态属性:

    TimeUnit.DAYS;               //天
    TimeUnit.HOURS;             //小时
    TimeUnit.MINUTES;           //分钟
    TimeUnit.SECONDS;           //秒
    TimeUnit.MILLISECONDS;      //毫秒
    TimeUnit.MICROSECONDS;      //微妙
    TimeUnit.NANOSECONDS;       //纳秒

    BlockingQueue<Runnable> workQueue:一个阻塞队列,用来存储等待执行的任务

    <pre name="code" class="java">ArrayBlockingQueue;
    LinkedBlockingQueue;
    SynchronousQueue;

    
    


    上面代码中使用的是ArrayBlockingQueue阻塞队列,并传入了参数5。这里有一点需要注意一下,如果我们假设所有任务数为mTaskCount(即代码中的15),那么我们最好去满足这样一个公式:maximumPoolSize >= mTaskCount - corePoolSize,不然就会抛出一个java.util.concurrent.RejectedExecutionException异常。当然,你也可以有一个通用的行为:将maximumPoolSize设置为Integer.MAX_VALUE。


    还有一种方式可以补救:

    ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());


    不过目前可能大家对ThreadPoolExecutor的使用可能也不那么频繁了。因为Java为我们封装好了一些更方便的创建方式:

    ExecutorService executor1 = Executors.newFixedThreadPool(5); // 创建固定容量大小的缓冲池
    ExecutorService executor2 = Executors.newSingleThreadExecutor(); // 创建容量为1的缓冲池
    ExecutorService executor3 = Executors.newCachedThreadPool(); // 创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE

    下面是上面三种创建方式对应的结果输出:

    创建固定容量大小的缓冲池

    正在执行task 0
    正在执行task 2
    正在执行task 4
    正在执行task 1
    正在执行task 3
    task 4执行完毕
    正在执行task 5
    task 0执行完毕
    正在执行task 6
    task 2执行完毕
    正在执行task 7
    task 1执行完毕
    正在执行task 8
    task 3执行完毕
    正在执行task 9
    task 5执行完毕
    task 7执行完毕
    正在执行task 10
    task 6执行完毕
    正在执行task 11
    正在执行task 12
    task 9执行完毕
    正在执行task 13
    task 8执行完毕
    正在执行task 14
    task 11执行完毕
    task 12执行完毕
    task 10执行完毕
    task 13执行完毕
    task 14执行完毕


    创建容量为1的缓冲池

    正在执行task 0
    task 0执行完毕
    正在执行task 1
    task 1执行完毕
    正在执行task 2
    task 2执行完毕
    正在执行task 3
    task 3执行完毕
    正在执行task 4
    task 4执行完毕
    正在执行task 5
    task 5执行完毕
    正在执行task 6
    task 6执行完毕
    正在执行task 7
    task 7执行完毕
    正在执行task 8
    task 8执行完毕
    正在执行task 9
    task 9执行完毕
    正在执行task 10
    task 10执行完毕
    正在执行task 11
    task 11执行完毕
    正在执行task 12
    task 12执行完毕
    正在执行task 13
    task 13执行完毕
    正在执行task 14
    task 14执行完毕

    创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE

    正在执行task 0
    正在执行task 2
    正在执行task 4
    正在执行task 6
    正在执行task 8
    正在执行task 10
    正在执行task 12
    正在执行task 14
    正在执行task 1
    正在执行task 3
    正在执行task 5
    正在执行task 9
    正在执行task 7
    正在执行task 11
    正在执行task 13
    task 2执行完毕
    task 8执行完毕
    task 6执行完毕
    task 4执行完毕
    task 0执行完毕
    task 10执行完毕
    task 14执行完毕
    task 12执行完毕
    task 1执行完毕
    task 3执行完毕
    task 5执行完毕
    task 7执行完毕
    task 9执行完毕
    task 13执行完毕
    task 11执行完毕


    RejectedExecutionException异常:

    http://blog.csdn.net/wzy_1988/article/details/38922449


  • 相关阅读:
    【Python 基础】For 循环的小例子
    Windows下部署Flask的Web服务
    Windows7 使用docker toolbox安装docker
    Docker容器中文乱码(修改docker容器编码格式
    docker windows 相关操作
    Flask Post 获取json数据,小文件实例
    python pyodbc mssql
    为什么未来10到20年,居家养老是蓝海产业
    Amazon的PRFAQ
    php数组排列组合(递归形式),可用于服装等商品规格的排列组合
  • 原文地址:https://www.cnblogs.com/fengju/p/6336088.html
Copyright © 2020-2023  润新知