java中的ThreadLocal

今天测试那边在做压力测试的时候,发现新版本的Jdbc占用CPU很高,导致并发量降低,研究半天,发现出问题的地方在于每条语句执行过后都会调用ThreadLocal的get方法。研究一番ThreadLocal…

问题背景

每次sql语句执行结束之后,最后都会接受后台传回的ReadyForQueryPacket包,标记语句执行完毕。在新版本的协议当中,针对读写分离的功能,在这个包中增加了一些要接收的数据:标记数据库主机状态的lsn。这个lsn标志着主备机之间的数据是否存在差异。每次执行完sql语句之后,都要将数据库后台传回来的lsn与当前主机的lsn进行比较,从而决定下一步的读写过程。每次取本机的lsn操作长这样:

1
LsnVo lv = ((LsnVo)DispatchConnection.threadLocalLsn.get());

其中,threadLocalLsn是DispatchConnection中的一个ThreadLocal类的静态对象。由于每次执行sql语句之后都会执行它的get方法,导致不必要的cpu浪费。这就是cpu异常的原因。

遂改之:

1
LsnVo lv = ((DispatchConnection) conn).getLsnVo();

阅读全文 »

通过HashMap认识equals与hashcode

最近读了HashMap的源码,对HashCode与equals有了一定的了解,总结一下,顺便理一下HashMap中的核心算法。

什么是hashcode,hashcode的作用是什么

hashcode并不是java中独有的。设想一下,如果让你设计一个算法,根据关键码去得到一个集合中的某个值或者这个关键码所在的位置。普通的做法就是挨个比较,高级一点的使用二分检索或者树形检索等算法。但是以上的检索算法都跟集合的长度N有关,当问题规模N很大时,这些检索的效率可能十分低下。

理想的情况是,根据关键码,我们就可以定位记录所在的位置,而不用去挨个进行比较。也就是说,在关键码与记录存放的位置之间做一种映射。这个映射的方法就是hash(哈希)函数,或者叫散列函数,也就是java中的hashCode()方法,他所返回的值就是hashcode,根据hashcode可以找到记录的位置。

按照散列的存储方式构造的存储结构叫做散列表。散列表中的一个位置称之为一个槽。

hashCode()方法存在于java.lang.Object类当中,任何类都可以继承修改这个方法。hashCode()方法返回调用它的实例的hashCode值,是个int值。

注:以下代码均来自jdk1.7

String中hashCode()方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}

阅读全文 »

java中的类型转换

以前一直对java中的类型转换了解的不是很清楚,因为平时写代码有IDE的帮助,所以往往忽略这一块的内容,但往往就是这样的小知识点不清楚,很有可能造成很大的错误。所以在闲暇时间总结一下这些可能被遗忘的知识点。网上已经有很多相关的介绍文章了,现在来梳理一番:

基本类型

  • 基本类型优先级

首先来看java中的基本类型有哪些:

byte:byte数据类型是一个8位有符号二进制补码整数。

short:short数据类型为16位有符号二进制补码整数。

int:int数据类型是一个32位有符号二进制补码整数

long: long数据类型是一个64位二进制补码整数

float: float数据类型是单精度、32位、符合IEEE 754标准的浮点数

boolean: boolean数据类型只有两个可能的值:true和false

double: double数据类型是双精度、64位、符合IEEE 754标准的浮点数;

char: char数据类型是一个16位的Unicode字符

基本类型优先级由低到高排序:

(byte short char) int long float double

其中,byte short char 平级

阅读全文 »

ANT编译java工程经jdk路径的设置

今天工作的时候涉及到使用ant对项目进行编译,打包。此前只知道ant是一个构建工具(当然,现在也是),也基本上没有接触过。但是build.xml是从仓库下载的已经配置好的文件。本来想着只要在eclipse轻轻一点Ant Build 就万事大吉,但是这个打包却折腾了我两个小时。

打包过程中总是报:

1
2
3
4
[javac] 警告: [options] 未与 -source 1.5 一起设置引导类路径
[javac] E:\doc\oscartools\driver\oscarJavaDriver\jdbc\V1.0\build\com\oscar\Driver.java:50: 错误: com.oscar.Driver不是抽象的, 并且未覆盖java.sql.Driver中的抽象方法getParentLogger()
[javac] public class Driver implements java.sql.Driver {
....

类似这样的一堆错误。

没有过多的思考,百度之…出现了一堆没用的资料和争论。80%的时间花在了看这些人扯淡上面(或许正真的大神并不关注这些问题)。

严重的浪费时间和影响心情,遂放弃。

静下来想想,工程的java build path使用1.5,java compiler 使用1.5,没什么问题啊。。。

后来灵光一现,build.xml中的javac难道与java home有关(原谅我现在才想到)?java home使用jdk为1.7,遂改为1.5。

重启eclipse,悲催,eclipse要求jdk必须大于等于1.7。

等等,如果不同的工程依赖不同的jdk的话,修改java home并不是一个明智的解决方案,一定可以针对某个工程修改它所依赖的javac,谷歌之 ‘ant set java_home in build.xml’

果然,stackoverflow拯救了我,只需要在build.xml文件中javac标签下添加

1
2
executable="C:\Program Files\Java\jdk1.5.0_22/bin/javac"
fork="yes"

阅读全文 »

java中的编码问题

最近在工作过程中总是被编码困扰,出现了很多意想不到的情况。故上网查看资料,总结一番。

2016/9/11 更新:今天在网上看到一篇讲解有关编码的文章 Java中字符编码和字符串所占字节数,个人认为作者写的十分清晰明了。把文章中的例子看懂的话再遇到乱码的情况解决起来应该不难!

编码

什么是编码?程序员应该都知道计算机能够识别的只是1和0,我们看到的文字、图片、视频等在计算机的 世界里都是以二进制的形式存在的。包括你的硬盘或者网络上传输的字节序列,都是无数个0和1组成的。英文字母,数字,汉字等都是字符。不同字符对应二进制数的规则,也就是说不同的字符翻译为不同的0、1组合,就是字符的编码。这个过程的逆过程,就是解码。

标准的ASCII编码使用的是7(2^7 = 128)位二进制数来表示所有的大小写字母、数字和标点符号已经一些特殊的控制字符,最前面的一位统一规定为0。(一个字节8位)。缺点是只能显示128个字符,显示的字符十分有限,比如对中文就无能为力了。

GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。

事实上世界上那么多国家,存在更多的字符是前面的编码所不能表示的。不同国家的不同编码之间也不能够兼容。所以就需要一套通用的编码能够表示世界上所有的符号,这就是Unicode编码
事实上,Unicode也是一套字符集。

阅读全文 »

关于抽象类和接口

抽象类:

使用了关键词abstract声明的类叫作“抽象类”。如果一个类里包含了一个或多个抽象方法,类就必须指定成abstract(抽象).

  • 抽象类不能被实例化

  • 如果一个类继承了抽象类,则该类必须实现所继承抽象类的所有抽象方法,否则该类也必须声明为abstract类

  • 抽象方法必须为public或者protected,缺省情况是public。若声明为private,则子类无法实现该方法。

  • 可以有抽象的构造方法,但该方法不能被用来实例化对象,只能由继承该类的子类通过super()调用。

  • 不可以有抽象的静态方法。因为在java中,静态方法是不可以被继承的,与抽象类的定义矛盾。

  • 抽象类不一定必须包含抽象方法,但包含抽象方法的类一定是抽象类。

  • 子类中的抽象方法不能与父类的抽象方法同名

  • 其余情况抽象类与普通类相同。

阅读全文 »