1.线程阻塞主要有以下四方面原因:
a.线程执行了Thread.sleep(int n)方法,线程放弃CPU,睡眠n毫秒,然后恢复运行.
b.线程要执行一段同步代码,由于无法获得相关的同步锁,只好进入阻塞状态,等到获得了同步锁,才能恢复运行.
c.线程执行了一个对象的wait()方法,进入阻塞状态,只有等到其他线程执行了该对象的notify()或notifyAll()方法,才可能将其唤醒.
d.线程执行IO操作或进行远程通信时,会因为等待相关的资源而进入阻塞状态.


具体到进行远程通信时,在客户端,线程在以下可能进入阻塞状态:
a.请求与服务器建立连接时,即当线程执行Socket的带参数的构造方法,或执行Socket的connect()方法时,会进入阻塞状态,直到连接成功.此线程才从Socket的构造方法或connect()方法返回.
b.线程从socket的输入流读入数据时,如果没有足够数据,就会进入阻塞状态,直到读到了足够的数据,或者达到输入流的末尾,或者出现了异常,才从输入流的read()方法返回或异常中断.输入流中有多少数据才算足够呢?看read方法类型.
int read():只要输入流有一个字节就足够;
int read(byte[] buff)只要输入流中的字节数与参数buff的数组长度相同就足够.
String readLine():只要输入流中有一行字符串就算足够.注:InputStream没有readLine方法,在过滤流BufferedReader中有此方法.
c.线程向socket输出流写一批数据时,可能会进入阻塞状态,等到输出了所有的数据.或者出现异常,才从输出流的write方法返回或异常中断.
d.调用socket的setSoLinger方法设置了关闭Socket的延迟时间,那么当线程执行Socket的close方法时,会进入阻塞状态,直到底层socket发送完的所有剩余数据,或者超过了setSoLinger()方法设置的延迟时间,才从close方法返回.


在服务器程序中,线程在以下情况下可能会进入阻塞状态.
a.线程执行ServerSocket的accept方法,等待客户的连接,直接接收到了客户连接.才从Accept()方法返回.
b.线程从Socket的输入流读入数据时,如果输入流没有足够的数据,就会进入阻塞状态.
c.线程向Socket的输出流写一批数据时,可能会进入阻塞状态,等到出了所有的数据,或者出现异常中断.


ServerSocketChannel:ServerSocket的替代类,支持阻塞通信与非阻塞通信.
SocketChannel:Socket的替代类,支持阻塞通信与非阻塞.
Selector:为ServerSocketChannel监控接收连接就绪事件,为SocketChannel监听连接就绪,读就绪和写就绪事件.
SelectionKey:代表ServerSocketChannel及SocketChannel向Selector注册事件的句柄.当一个SelectionKey对象位于Selector对象的Selected-keys集合时,就表示与这个SelectionKey对象相关的事件发生了.


Selector类:
all-keys:当前所有向Selector注册的SelectionKey的集合,
selected-keys:相关事件已经被Selector捕获的Selection的集合.
cancelled-keys:已被取消的SelectionKey的集合.