??xml version="1.0" encoding="utf-8" standalone="yes"?>
1、thread-per-request 的方式,q样会有更多U程l护和切换的pȝ开销Q同时在pȝ扩展性方面受到限制?/span>
2、针寚w?Q我们可以采用线E池的方式来节省U程创徏、维护以及切换的开销Q但是这样也会限制系l可以同时处理客L的数量,臛_对一些长q接协议来说是这栗此时增加线E池的大是不能再提高系l性能的,而只会增加系l更多的U程开销?/span>
3、传l的socket在读/写数据以及徏立连接上都是d式的(没有数据可读可能会阻塞;没有_I间~存传输的数据可能阻塞;服务端的acceptҎ以及socket构造函数都会阻塞等待,直到q接建立) 。这些特性会降低整个pȝ对CPU的利用率以及pȝ的活跃性,降低pȝ对客戯求的响应性及响应旉Q在某些情况下是不可接受的甚至会带来N性的l果。在q样的情形下Q我们要解决cpu利用率、线E活跃性以及提高系l吞吐量Q我们势必做很多额外的工作且相当复杂?/span>
4、由于传lsocket的阻塞特性,每个对等端都在阻塞等待另外一端完成相兛_理,q样势必增大死锁的风险?/span>
5、当然ؓ了提高系l的z跃性,传统的socket在accept、构造socket以及readҎ上都增加了超时控制的处理以及使用socket.closeҎ来打断一些阻塞操作,而网lL不确定的Q设|这些超时时间的讄在具体的上下文环境中的取g是比较复杂的。简而言之,Z提高pȝ的活跃性会增大pȝ的复杂度?/span>
那么QJava nio真的是Java socket~程解决以上若干问题的灵丹妙药吗?{案是否定的?/span>
nio的非dҎ是nio最大的特点Q所谓非d无非是通信的信道设|成为非d的情况下Q对该信道的所有操作都是会立即q回的。如数据dQ没有数据的时候会q回0而不是阻塞在信道上。这样就增大了系l的z跃性,使得pȝ不必费资源的I/O操作上,pȝ可以更好的利用cpu资源做一些其它处理,在某些场景下会提高系l的响应性以及吞吐量?/span>
同时nio在网l通信的中采用的网lI/O事g驱动的方式,x作系l对用户感兴的通信信道及其上面的I/O事gq行监听q知应用E序。这实际上也是观察者模式的一U应用,在这L背景下,问题4中的死锁风险几乎没有了?/span>
如果你开发的服务端不是P代服务器(序化处理每个客戯?Q那么对于问??在nio服务器中也是一L。换句话_我们开发的q发处理服务器ؓ了实现对各种|络I/O事g的处理,q对每种我们所兛_的网lI/O事gq行及时响应Q采用thread-per-request或者线E池的方式是无法避免的。所以很多h会感觉nio的网l编E结构与非nio的网l编E结构实际是一LQaccept换成了selectQ监听连接入站编E了监听信道上感兴趣的I/O事gQؓ了提高系l的处理能力Q还是要启动异步的线E来处理信道上的|络I/O事gQ只是具体实C一栯已。这说明nioq没有改变我们服务端E序~写的整体结构,只是在nio的环境下Q我们的可以去提高pȝ的活跃性、响应性和吞吐量。nio与非nio在读/写网l数据以及连接徏立等|络操作上是没有多大区别的,q些因素主要都还是取决于|络状况、操作系l协议栈实现、应用自w处理网l数据的方式{多个方面。甚臻I我们在n用nio的同时在一定程度上q会增大了网l编E的复杂度,因ؓ数据的读写以及连接的建立{操作变得更加不定Q当然最l网l编E的复杂q是取决于协议的复杂度?/p>
ThreadLocal很容易让使用者误?以前我就误解?Q因为在q个cM定义了一个静态的包可见的内部类ThreadLocalMapQ同时ThreadLocal对外提供了get和setҎ。那么set的时候就是把当前U程对象作ؓThreadLocalMap的keyQ把传入setҎ的g为value存储hQget的时候通过获取当前U程对象Q然后到ThreadLocalMap中取得对应的value。这U认识是表面的很Ҏ理解的方式,但是也是错误的理解?/font>
每个ThreadcM都有ThreadLocal.ThreadLocalMap的两个成员,分别是threadlocals与inheritableThreadLocals。前者用来存储当前线E的相关数据信息Q后者用来存储从父线E中l承或者说拯q来的相x据信息。这两个区域也就是前面提到的U程的特别存储区域,但是如何操作它们QJDK中的设计q不是让用户直接操作当前U程来存取数据,而是让用h作ThreadLocal来对当前U程的这两个Mapq行存取(个h认ؓq样设计是出于安全性与易用性考虑Q主要是Map中的key值需要固定才能取到同一对象)Q同时放|在q两个Map中的key值就是ThreadLocal对象自nQvalueq户传入?/font>
ThreadLocal为线E独占某些对象或者资源提供了新的手段QThreadLocal与线E堆栈都是用来存取线E私有数据的区域Q别的线E无法触这两个区域Q但是二者确有不同的生命周期。这个可以这L解,U程跨多个方法调用的时候,Ҏ作ؓFrame不断的进栈和出栈(Ҏ的调用与q回)Q同时出栈的时候方法中的时变量数据会被回Ӟ在这个线E的堆栈中消失,所以方法中的局部变量是无法在线E调用过E中IK,除非是传递局部的引用cd变量Q但是这也意味着Ҏ接口都要额外接收新的参数(早期pȝ中传递JDBC数据库连接的方式)。而ThreadLocal不同Q准地说是U程中的ThreadLocalMap不同Q线E对象中的ThreadLocalMap对象是伴随整个线E对象生命周期的Q线E可以在M需要的时候通过它来获取相关数据Q这为线E独占数据提供了一U更加优雅的方式。只不过q一切都是通过ThreadLocal来操作的而已Q同时ThreadLocal自n也作Z同线E中的ThreadLocalMap中的key来映存入的value?br />
public class ThreadWriter
{
private static final ThreadLocal<FileWriter> local = new
ThreadLocal<FileWriter>();
public void write(String s)
{
try
{
getFileWriter().write(s);
}
catch(IOException e)
{
//igore
}
}
private FileWriter getFileWriter()
{
FileWriter fw = local.get();
if (null == fw)
{
try
{
fw = new FileWriter(Thread.currentThread().getName() + "-info.txt", true);
local.set(fw);
}
catch(IOException e)
{
//igore
}
}
return fw;
}
} q里说明几个问题Q?/font>
1?nbsp;ThreadLocal对象只有一份,它将作ؓ不同U程中的ThreadLocalMap对象的keyQ所映射的值是不同文g路径的FileWriter对象。只不过不同 U程中的ThreadLocalMap中的key值都一P但是因ؓ在不同的ThreadLocalMap中,不会有Q何媄响,反而这L方式为每个线E中ThreadLocalMap对象中的key值生成省M很多功夫Q这是一个很_֦的设计,用户在间接用ThreadLocalMap的时候,不需要感知key是什么,可以方便地存取?/font>
2?nbsp;一份ThreadLocal对象只能映射一U资源。如需要映多U资源的话,定义多个ThreadLocal成员?/font>
3?local.set(fw); q句代码表示local自n作ؓkeyQfw作ؓvalueQ存储在调用q行代码的线E中的ThreadLocalMap对象中?/font>
FileWriter fw = local.get(); q句代码表示local自n作ؓkeyQ从当前U程的ThreadLocalMap对象中取出属于自q占的FileWriter对象?/font>
ThreadLocal q阶
ThreadLocal 应用
]]>