最近还是要好生学习了,做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()方法,就是前者有返回值,后者没有。