May 20

Process waitFor无法返回原因分析

    今天做一个mysql数据恢复的小程序,采用Runtime.exec的方式来执行mysql命令。主要用来恢复一些由定时程序自动备份出来的数据库文件,有时候可能会出现恢复的数据在数据库中还存在,于是会出现主键重复的错误,于是我在恢复的时候加入–force参数,手动在cmd控制台下执行可以很明显看到mysql返回了一些duplicate的error,按道理在java app中也能正常执行过去,可在执行java app的时候看控制台中打印的日志显示,程序阻塞在了waitFor这一步。我的程序片段如下:
……   
p = Runtime.getRuntime().exec(cmd);
……
    p.waitFor();
……
    百思不得其解,最后在google了下,找到一片最早分析该原因的文章是在javaworld上。原因是操作系统这一层对输入输出流有一个buffer,由于受到这个buffer的大小限制,当buffer满了而又没有线程去读,则当前执行的线程就会阻塞掉,于是修改一下程序,开辟两个线程专门用于读取输出流,一个用于读取返回消息流,一个用于读取异常消息流,于是修改程序如下:
……
p = Runtime.getRuntime().exec(cmd);
   
new PrintStream(p.getInputStream()).start();
new PrintStream(p.getErrorStream()).start();
p.waitFor();
……
此处PrintStream为一个读取inputstream的线程。

Jan 09

Java位运算

      Java算是一门很高级的语言了,平时使用一般不会用到位运算这种很低级的特性,但在有些地方有很高的性能或者空间的要求可能会用到,比如说手机平台。今天偶尔看了下,发现一些基础只是很长时间没有搞都忘记了,今天看到相关的东西以至于想了很久才想通。就从今天看到的一段代码来回顾些基础知识,是一段将int转换为byte数组的代码。

———————————————————–
//cout为自己包装的打印方法
  int a = 645765765;
  cout(a);
  cout(Integer.toBinaryString(a));
  byte[] b = new byte[4];
     b[0] = (byte)((a>>24)&0xff);
     cout(Integer.toBinaryString(b[0]&0xff));
     b[1] = (byte)((a>>16)&0xff);
     cout(Integer.toBinaryString(b[1]&0xff));
     b[2] = (byte)((a>>8)&0xff);
     cout(Integer.toBinaryString(b[2]&0xff));
     b[3] = (byte)((a>>0)&0xff);
     cout(Integer.toBinaryString(b[3]&0xff));
    
     int decodeA ;
     decodeA = b[0]&0x000000ff;
     decodeA = (decodeA<<8) + (b[1]&0xff);
     decodeA = (decodeA<<8) + (b[2]&0xff);
     decodeA = (decodeA<<8) + (b[3]&0xff);
     cout(decodeA);
//自己写的另外一种转换方法
     int decodeA2 ;
     decodeA2  = ((b[0]&0xff)<<24);
     decodeA2 += ((b[1]&0xff)<<16);
     decodeA2 += ((b[2]&0xff)<<8);
     decodeA2 += ((b[3]&0xff)<<0);
     cout(decodeA2);
——————————————————————–

      一开始看到的黑体部分。于是写了下面红色的版本,但之前不是现在这个正确版本,之前是这样的。
     int decodeA2 ;
     decodeA2  = b[0]<<24;
     decodeA2 += b[1]<<16);
     decodeA2 += b[2]<<8;
     decodeA2 += b[3]<<0;
     cout(decodeA2);
    结果只要a的值一超过128就会出错,百思不得其解,之后查了有关移位的资料。右移在java中有两种方式,一种是带符号的,一种是不带符号的,带符号的会根据最高位的值来判断用1还是0来补足,若最高位为1则用1来补,若为0则用0来补,无符号的则全部用0补,而对于左移则全部用0补。想了很久这个似乎也没有关系,最后偶然间看到byte的最高位是用来表示正负的,就是说byte的值为-128到127,所以只要在遇到了某一byte的最高位为1的情况下就会出现该值变为了一负值,但其实这个时候它里面存的位信息还是对的,用Integer的int到二进制的一个方法将其打出来便可以发现是一个32位的高位全为1的二进制形式,及是一个负数,于是对它在进行一次“与运算”去掉高位的“1”就可以得到正确的结果了。

May 26

Linux下配置java环境

    早就想玩儿玩儿linux了,最近从同事那儿弄来了一个redhat linux的安装好了的虚拟机映像回来,直接用vmware打开就可以用,省了很多事儿。redhat也有带一个xwindow界面,看上去也挺漂亮。由于是用虚拟机装的,玩儿起界面来还是有点儿卡,后来同事说把它启动起来了搞了一个SecureCRT连接上去用命令行操作会舒服很多,就又搞了一个SecureCRT,感觉是屌了很多。下面言归正传,开始装java环境。 Continue reading

Apr 06

java加密解密学习心得

    在java中可以利用keytool工具生成非对称密钥对(PrivateKey和PublicKey),PublicKey和PrivateKey也 可以用KeyPairGeneerator来生成.keytool工具生成的密钥对保存在keystore文件中,这个keystore中可以保存多个密 钥对,每个密钥对都有一个唯一的名称(alias)与之对应,可以选择从这个keystore中导出某一个名称对应的密钥对的公钥,导出后的公钥叫做数字 证书,就是说数字证书中保存的就是一个公钥.而从keystore中导出的数字证书与一般自己生成的公钥是有区别的,数字证书能够将一个公钥与某个具体的 实体相对应(人或者企业机构),这个数字证书是否受到信任取决于你是否信任该证书的证书链上的任意一个颁发机构.如果证书受到信任即可以确认该证书中存储 的公钥确实是属于某个实体.在java中利用数字证书对信息进行签名,实质上做的事情是,先取得信息的摘要,然后对摘要进行数字签名(即用自己的私钥对摘 要进行数字签名).因此使用数字证书可以实现两个功能:防止信息被篡改(由摘要实现),防止抵赖(消息摘要是用自己的私钥进行的签名).举例:A要跟B通 信,A有B的证书(B的公钥),B有A的证书(A的公钥),A要给B发送信息的话,A就用自己的私钥对信息进行签名,接着将签名与要发送的信息一起发送给 B,B收到签名与信息后,用A的证书(A的公钥)验证签名,如果验证通过则B可以确信两件事情,第一信息在传输过程中没有受到篡改,第二,改信息确实由A 发送而来。 Continue reading