打印GB2312编码中的所有汉字
- for(int j=0xB0; j<0xF8; j++)
- {
- for(int i=0xA1;i<0xFF;i++)
- {
- byte[] bytes = new byte[2];
- bytes[0] = (byte)j;
- bytes[1] = (byte)i;
- System.out.println(new String(bytes));
- }
- }
首先不得不说这个类org.apache.tomcat.util.net.JIoEndpoint,它负责所有的TCP请求连接,实现了一个服务器模式,启用一个后台监听线程,负责接收到来的socket,然后从线程池中取出响应的worker,扔给worker进行处理,自己继续监听。其次worker是一个负责处理socket的一个线程,就是它带着用户的请求开始进入Tomcat世界的,默认的worker总共有200个,即:最多200个线程。当处理完一个请求的时候,这个线程并不会销毁,而是进入wait阻塞,这个线程的对象也不会销毁,是进入了一个栈里面,对应workstack那个数据结构。每当接收线程拿到一个socket的时候,就先从栈里面拿出一个已有的线程对象,然后就利用该对象的assign方法,将这个socket给它,并调用notify重新唤醒这个worker的处理线程。以后我们做小型服务器的时候,可以借鉴它的实现方式。正在研究多线程的朋友,这个类绝对让你可以学的透彻!
相对应的还有一个org.apache.tomcat.util.net.NioEndpoint,这个和前面那个功能差不多,但是用了NIO包里的API,有一个最大的区别就是,接收线程接收一个socket之后,可能会将这个socket先放入缓存池,然后worker从池里面拿socket去处理,比前面那个类看起来功能和性能都会提升很多,不过代码行有2K多,相当复杂,设计不够精巧,有兴趣可以去研究下。
org.apache.tomcat.util.buf.MessageBytes:这是一个接近底层的字符串处理类,为什么说是接近底层,是因为socket接收进来的都是字节类型,而java用的是char或者String,这之间的转换涉及到编码问题和性能问题,所以凡是socket收进来的信息,全部都用这个类表示,只有当要输出字符串的时候,才会将里面的字节进行转换,实现一种延迟加载的懒模式,被Tomcat底层所使用的Request类,就是大量使用了这个类来存放数据。我们来小小窥视一下,Request类:
或许大家会觉得,构造出这么多的类,性能会高到哪里去,其实不是这样的,不停的构造和销毁对象的确会损耗相当的性能,但是一个对象被构造出来,可以重复利用,那就相当完美了,这个类就是如此的设计,其中有一个回收资源的方法,叫recycle(),这个方法可以清空里面的数组,清空里面的对象,而不会销毁自己本身,因为使用它的对象,只要调用recycle,以后又可以重复使用了。
MessageBytes其实内置了2个重要的类,org.apache.tomcat.util.buf.ByteChunk和org.apache.tomcat.util.buf.CharChunk,这2个类带我们回到了C时代,为什么这么说?因为它简直就是一个字符串处理类,一些眼熟的算法全部映入眼帘,比如字符转匹配算法,indexOf,startsWith,判断字符转是否相等,查找字符,等等,比之JDK提供的性能更好,功能更强大(这句话说过了,呵呵)
还有一个实用的值得学习的数据结构是,org.apache.tomcat.util.buf.Ascii,如果知道表驱动的朋友们,一定对这个类很熟悉了,判断大小写?判断是不是英文单词?判断是不是空白符?判断是不是数字,将字节类型转换为int、long类型,大小写转换,等等。这些都是大学计算机课程的课后练习题。
下面代码的大致思路是:传入一个socketServer得到的socket的,然后再建立一条到其他代理服务器的socket的,接着就是按照顺序来回倒数据,只要读入的数据不是-1,那么就有可能再读到数据,这2条通路的任何一条通路读入数据为-1,那么就结束。其次还有退出循环的可能就是,在读数据的时候发生异常,有2种情况会产生这种异常,要么浏览器认为没有数据可以读了,要么代理服务器那里认为没有数据可以写过来了,那么它们就会close它们各自的socket,此时我们再尝试读socket,就会报错:socket已经被断开。
一直以来都想好好研究下ReentrantLock,她的独到魅力令我屡试不爽,无奈网上实在是没有太多的资料可以参考,于是自己开始深入研究它的内部实现机制,经过数天的研究,终于有点心得体会升华了,记录之……
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……
先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考下相关资料,再回头看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵)
这里来做个试验,首先搞一个Buffer类,它有读操作和写操作,为了不读到脏数据,写和读都需要加锁,我们先用synchronized原语来加锁,如下:
接着,我们来定义2个线程,一个线程去写,一个线程去读。
好了,写一个Main来试验下,我们有意先去“写”,然后让“读”等待,“写”的时间是无穷的,就看“读”能不能放弃了。
我们期待“读”这个线程能退出等待锁,可是事与愿违,一旦读这个线程发现自己得不到锁,就一直开始等待了,就算它等死,也得不到锁,因为写线程要21亿秒才能完成 T_T ,即使我们中断它,它都不来响应下,看来真的要等死了。这个时候,ReentrantLock给了一种机制让我们来响应中断,让“读”能伸能屈,勇敢放弃对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
当然,要对reader和writer做响应的修改
这次“读”线程接收到了lock.lockInterruptibly()中断,并且有效处理了这个“异常”。好奇的读者,肯定要探个究竟,为什么ReentrantLock能做到这点,接下来,我们去迷宫探险吧……
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到内存,等要用了,再还原到对象中,说白了,就是能将一个2进制文件变成内存中的对象。在JAVA中,要实现这种机制,只要实现Serializable接口就可以了,先看下面这个简单例子,serialVersionUID稍后引出。我们先定义一个简单的Person类,然后创建这个对象,最后序列化它到一个文件。
运行完后,我们发现有了一个crab_file文件,这个文件就保存这crab对象在内存中的形态。同样,我们把这部分代码注释掉,运行下面那段还原代码,发现,crab_file文件可以被转化为一个对象。
一切都那么顺利,但是如果在序列化之后,Person这个类发生了改变呢?比如,多了一个成员变量。我们做如下试验,还是先将对象序列化到一个文件中,之后在Person这个类中添加一个成员变量,如下:
之后,我们再去运行一下还原,就发现运行出错了,会报如下错误:
Exception in thread “main” java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = 8383901821872620925, local class serialVersionUID = -763618247875550322
意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。之前,在我们的例子中,我们是没有指定serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,我们添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个号码不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法可以用,呵呵。但是serialVersionUID我们怎么去生成呢?你可以写1,也可以写2,都无所谓,但是最好还是按照摘要算法,生成一个惟一的指纹数字,eclipse可以自动生成的,jdk也自带了这个工具。一般写法类似于
private static final long serialVersionUID = -763618247875550322L;
iphone已经用了一年半了,自从1.13版本以来就再也没有刷机过了,感觉硬件水平不变的情况下,软件平台本身是不会有质的飞跃的,但是前几天刷机到2.21之后,我发现自己真的落伍了,没想到这个一代的老iphone还是能发挥的如此出色,现在的3方软件也是五花八门,层出不穷,比起以前每用一个软件就失望一次比起来,这次真是给我带来太多的惊喜,下面是截图。
首先是主页面


地图导航,能找到我在哪个位置,要去哪里,怎么走…居然把GPS模仿的这么好


另外,UCWEB,飞信,QQ,同花顺,彩信等常用软件都用的非常爽






最大的进步莫过于游戏了,想1年半之前,iphone刚推出那会儿,啥游戏都没有,装个GBA、PS2模拟器就乐呵乐呵了,看看现在这么多的游戏,真是再次令人惊叹。感谢网龙公司为大家贡献的这些,呵呵。
在看myfaces源码的时候,一直不明白javax.faces.webapp.FacesServlet中有一段
其中的FactoryFinder.getFactory是这样一段代码
注意其中的 _registeredFactoryNames.get(classLoader),说明在javax.faces.webapp.FacesServlet之前_registeredFactoryNames已经构造好了,可是我查web.xml的时候,根本找不到其它类了,到底谁去初始化了_registeredFactoryNames呢?
其实是 WEB-INF/lib/myfaces-impl-1.2.6.jar 这个引入的包起了作用,这里面有2个.tld文件,tomcat等j2ee容器会扫描所有的classpath,遇到.tld文件,也会去里面执行的。在myfaces_core.tld中,除了定义了一些f:开头标签以外,就有一段监听器代码
这才是整个myfaces加载的爆炸点。以前struts的爆炸点都是在web.xml定义的servlet中的,这次放在了jar包里面,正是有点不习惯,要是仅仅想用里面的一些功能,还非得加载这个玩意了,呵呵。
一个人的周末,自由也很寂寞;
手机为你,变成最依赖的玩具;
一个人的周末,期待变成泡沫;
思念暴走,像热带鱼一样游过;
一个人的摩卡,想象两个人的焦糖;
without爱装哲学的你,何处去流放我的幻想。
你说那边,忙忙碌碌风和日丽;
却不知道,我这里风大心也凉;
要你在身边,让雨停出太阳;
要你躺在肚皮上,让它告诉你,没有你我有多么的坚强。
悄悄许个愿望,变成拇指姑娘;
躲进你的口袋,陪你四处流浪;
你说要做我的muscle man,要我乖乖,等你归来;
我说我要许你一个未来,做你永远的only one。
此刻才明白,你对我的温柔,是我永远无法割舍的依赖。
YOYO作词于杭州下沙
CRAB 谱词于深圳龙岗
executatble files:
C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin
C:\Program Files\Microsoft Visual Studio\VC98\BIN
C:\Program Files\Microsoft Visual Studio\Common\TOOLS
C:\Program Files\Microsoft Visual Studio\Common\TOOLS\WINNT
include files:
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE
library files:
C:\Program Files\Microsoft Visual Studio\VC98\LIB
C:\Program Files\Microsoft Visual Studio\VC98\MFC\LIB
source files:
C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC
添加时要精确点,确保这些目录都找的到,而且后面不能有空格…