java 并发编程学习笔记(一)Executors框架

最近还是要好生学习了,做JAVA那么多年,笔记记了不少,但重来没写过BLOG,以后要养成好习惯大笑!学习计划是在2014的最后几个月了,再把JAVA并发编程认真学习一下(学习东西资料的出处当然还是书与网络呢),复习下以前搞的服务器方面的知识,最后再把android 包括telephoeny,framework都再梳理一遍。 好,写BLOG还是要给人看的,因此还是尽量写好一些。

言归正转:

在java多线程中一般我们写服务器,很常用的一种写法是

public class ChatServer{ 

  public static void main(String[] args)

 {

      ServerSocket s=new ServerSocket(8080);/*创建一个监视8080端口的服务器套接字, */

      for(;;)

     {

          Socket newjoin=s.accept();/*等待一个连接。如果该连接未被创建,本方法阻塞当前线程。返回值是一个Socket对象,服务器程序利用这个对象与连接的客户通信。*/

          Runnable task = new Runable(){

              handleClientRequest(newjoin);

         }

       new Thread(task ).start();

     }

   }

这种写法初期可以运行良好,但是线程的创建不是没有代价的(并且活跃的线程会消耗大量资源),后期由于用户数的增大,或者恶意攻击,服务器很容易崩溃。
Java自1.4以后,加入了新IO特性,NIO. 号称new IO.Executor框架将任务的执行与提交解耦开来,

此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。

1. newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

2. newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

3. newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

4. newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

Executor是一个接口,并且还有一个重要的接口是ExecutorService,他的有生命周期,主要是运行,关闭和终止

public interface ExecutorService extends Executor {
    /**
     * 关闭方法,调用后执行之前提交的任务,不再接受新的任务,注意的是他需要把之前没有执行完成的执行完
     */
    void shutdown();

    /**
     * 从语义上可以看出是立即停止的意思,将暂停所有等待处理的任务并返回这些任务的列表,即之前没有执行完的也要停止
     */
    List<Runnable> shutdownNow();

    /**
     * 判断执行器是否已经关闭
     */
    boolean isShutdown();

    /**
     * 关闭后所有任务是否都已完成
     */
    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException;

    /**
     * 提交一个Callable任务
     */
    <T> Future<T> submit(Callable<T> task);

    /**
     *返回 Callable 对象,调用它时可运行给定的任务并返回给定的结果。  
     */
    <T> Future<T> submit(Runnable task, T result);

    /**
     * 提交一个任务
     */
    Future<?> submit(Runnable task);

    /**
     * 执行所有给定的任务,当所有任务完成,返回保持任务状态和结果的Future列表
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException;


    /**
     * 执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
     */
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
            long timeout, TimeUnit unit) throws InterruptedException;

    /**
     * 执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException;

    /**
     * 执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout,
            TimeUnit unit) throws InterruptedException, ExecutionException,
            TimeoutException;
}


在这个接口中我们看到了sumbit方法,顾名思义他是提交一个任务,那么它和execute有什么区别了,我们从表象来看只是它有一个返回值Future,和一个传入参数为Callable接口,public interface Callable<V>这个接口定义了一个不带任何参数的叫做 call 的方法。Callable中的call()方法类似Runnable的run()方法,就是前者有返回值,后者没有。

 
当将一个Callable的对象传递给ExecutorService的submit方法,则该call方法自动在一个线程上执行,并且会返回执行结果Future对象。同样,将Runnable的对象传递给ExecutorService的submit方法,则该run方法自动在一个线程上执行,并且会返回执行结果Future对象,但是在该Future对象上调用get方法,将返回result
这里需要说明的是ExecutorCompletionService它将BLOCKQUEUEfuture结合起来可用于下载图像并且在获取feaure后将图片渲染出来,同时future 的get方法还可以设置超时时间,这是否和android 的asyncTask有异曲同工之妙,只有自己慢慢去体会了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值