一,多线程
从资源利用的角度看,使用多线程的原因主要有两个:IO阻塞与多CPU。当前线程进行IO处理的时候,会被阻塞释放CPU以等待IO操作完成,由于IO操作(不管是磁盘IO还是网络IO)通常都需要较长的时间,这时CPU可以调度其他的线程进行处理。理想的系统Load是既没有进程(线程)等待也没有CPU空闲,利用多线程IO阻塞与执行交替进行,可最大限度利用CPU资源。使用多线程的另一个原因是服务器有多个CPU,要想最大限度地使用这些CPU,必须启动多线程。
启动线程数=【任务执行时间 / (任务执行时间 - IO等待时间)】 * CPU内核数
即:如果任务是CPU计算型任务,那么线程数最多不超过CPU内核数;如果任务需要等待磁盘操作,网络响应,那么多启动的线程有助于提高任务并发度,提高系统吞吐能力,改善系统性能;
解决线程安全的主要手段主要有以下几点:
1,将对象设为无状态(虽然从面向对象的角度,这是一种不良设计);
2,使用局部对象;
3,并发访问资源时使用锁;
二,资源复用
系统运行时,要尽量减少那些开销很大的系统资源的创建和锁毁,比如数据库连接,网络通信连接,线程,复杂对象等。从编程角度,资源复用主要有两种模式:单例和对象池;对于每个WEB请求,WEB应用服务器都需要创建一个独立的线程去处理,这方面,应用服务器也采用线程池的方式。这些所谓的连接池,线程池,本质上都是对象池,即连接,线程都是对象,池管理的方式也基本相同;
三,数据结构
字符串散列算法Time33:
hash(i) = hash(i - 1) * 33 + str[i]
Time33虽然可以较好地解决冲突,但有可能相似字符串的HashCode也比较接近,这种情况下,一个可行的方案是对字符串取信息指纹,再对信息指纹求HashCode,由于字符串微小的变化就可以引起信息指纹(MD5)的巨大不同,因此可以获得较好的随机散列。
四,垃圾回收
理解垃圾回收机制有助于优化和参数调优,以及编写内存安全的代码。
以JVM为例,其内存主要可划分为堆(heap)和堆栈(stack)。堆栈用于存储线程上下文信息,如方法参数,局部变量靠等。堆则是存储对象的内存空间,对象的创建和释放,垃圾回收就在这里进行。
在JVM分代垃圾回收机制中,将应用程序可用的堆空间分为年轻代(Young Generation) 和年老代(old Generation),又将年轻代分为Eden区(Eden Space),From区和To区,新建对象总是在Eden区中被创建,当Eden区空间已满,就触发一次YoungGC,将还被使用的对象复制对From区,这样整个Eden区都是未被使用的空间,可供继续使用,当Eden区再次用完,再触发一次Young GC,将Eden区和From区还在被使用的对象复制到To区,下一次Young GC则是将Eden区和To区还被使用的对象复制到From区。因此经过多次Young GC,某些对象会在From区和To区多次复制,如果超过某个阈值对象还未被释放,则将该对象复制到Old Generation。如果Old Generation空间也用完,那么就会触发Full GC,即所谓的全量回收,全量回收会对系统性能产生较大影响,因此应该根据系统业务特点和对象生命周期合理设置Young Generation 和 Old Generation 的大小,尽量减少Full GC。事实上,某些WEB应用在整个运行期间可以做到从不进行Full GC。