零碎笔记(四)

来源:互联网 发布:电脑必装软件 编辑:程序博客网 时间:2024/05/19 10:11
JAVA中,当需要把一个类序列化的时候,显示提供一个serialVersionUID有什么用呢?
       a)小幅性能提升,免除JVM运行时对这个值的计算。
       b)避免java.io.InvalidClassException,不同的JVM对serialVersionUID的计算方法可能不一样,就算类的定义和序列化后的对象是一致的,也可能从JVM-A里序列化后的对象到达JVM-B后,JVM-B认为 Class Invalid。
       c)对象在序列化后,Class定义被改变了,如果明确提供了serialVersionUID,只要serialVersionUID不变,对象仍然能被正常的deserialize。不过,最好不要这么做。


Java的异常体系:
      Throwable(public class Throwable implements Serializable)是 Java 语言中所有错误或异常的超类。它有两个子类:Error和Exception。
      Error:用于指示合理的应用程序不应该试图捕获的严重问题。这种情况是很大的问题,大到不能处理了,不用管它。比如说VirtualMachineError:当 Java 虚拟机崩溃或用尽了它继续操作所需的资源时,抛出该错误。
      Exception:它指出了合理的应用程序想要捕获的条件。Exception又分为两类:一种是CheckedException,一种是UncheckedException。这两种Exception的区别主要是CheckedException需要用try...catch...显示的捕获,而UncheckedException不需要捕获。通常UncheckedException又叫做RuntimeException。对于可恢复的条件使用被检查的异常(CheckedException),对于程序错误(言外之意不可恢复)使用运行时异常(RuntimeException)。
      常见的RuntimeExcepiton有IllegalArgumentException、IllegalStateException、NullPointerException、IndexOutOfBoundsException等等。在编写程序过程中try...catch...捕捉的异常都是CheckedException。io包中的IOException及其子类,这些都是CheckedException。
       建议不要用一个Exception来捕捉所有的异常,从异常角度来说这样严格的程序确实是万无一失,所有的异常都能捕获。但是站在编程人员的角度,万一这个程序出错了该如何分辨是到底是哪种异常引起的呢,IO还是JDBC?
       将try block写的简短,不要所有的东西都扔在这里,尽可能的分析出到底哪几行程序可能出现异常,只是对可能出现异常的代码进行try。尽量为每一个异常写一个try...catch,避免异常丢失。


两台主机通信,数据从一台主机传到另一台主机主要有以下三步工作:
       1、主机A发送的数据进入线路
       2、数据在线路中传输
       3、数据从线路的另一端进入主机B中
其实第3步与第1步所做的事正好相反,先来看第1步中数据是怎么流动的?这个过程主要经过了以下步骤:
       1、应用程序将要发送的数据写到进程的地址空间(用户态内存区);
       2、应用程序通过系统调用将数据从用户态的内存区复制到内核维护的一段内核缓冲区中,由于内核缓冲区通常是有限的,所以这个过程需要排队。内核缓冲区的数据可能来自于多个进程;
       3、内核通知网卡控制器来取数据,网卡驱动器根据网卡驱动程序得到内核缓冲的地址,并将数据复制到网卡缓冲区,这个过程按连接两端的内部总线宽度来复制,比如32位总线每次复制32位比特;
       4、网卡缓冲区将数据发送到线路中,释放缓冲区准备下一轮复制,这些数据在这步都会转为2进制,因为只有2进制的数字信号才可以在线路中传输。发送时,网卡会根据介质产生各种信号。


       并非所有对象都适合拿来池化,因为维护对象池也要造成一定开销。对生成时开销不大的对象进行池化,反而可能会出现“维护对象池的开销”大于“生成新对象的开销”,从而使性能降低的情况。但是对于生成时开销可观的对象,池化技术就是提高性能的有效策略。


ForkJoinPool就是一个ExcuteService,与ExcuteService不同的是:
       1、ExcuteService执行Runnable/Callable任务,ForkJoinPool除了可以执行Runnable任务外,还可以执行ForkJoinTask任务;
       2、ExcuteService中处于后面的任务需要等待前面任务执行后才有机会执行,而ForkJoinPool会采用work-stealing模式帮助其他线程执行任务,即ExcuteService解决的是并发问题,而ForkJoinPool解决的是并行问题。


       JVM中可以生成的最大线程数量由JVM的堆内存大小、Thread的Stack内存大小、系统最大可创建的线程数量(Java线程的实现是基于底层系统的线程机制来实现的,Windows下_beginthreadex,Linux下pthread_create)三个方面影响。


为什么要重载equal方法?
       因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。
为什么重载hashCode方法?
       一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才需要重载hashCode。那么为什么要重载hashCode呢?就HashMap来说,其定位元素在Node<K,V>[]的位置时,是对key的hashCode进行hash的:
static final int hash(Object key) {    int h;    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
所以需要在HashMap中看两个key是不是相同,必须先判断hashCode相等(这样才会hash到同一个位置),然后才判断equal。所以如果是object对象为key的话,必须重载hashCode和equal方法。


        为了节约内存,Java String中内置intern方法,保留String的弱引用哈希表。在Java 6中这个表放在永久代,永久代的内存配置很固定,而且pool size不可配置,不方便。
       升级到java7之后,可以使用-XX:StringTableSize(默认1009)设置pool size(为了性能应使用素数)。从参考资料看,只要pool size够大,性能是很不错的。而且相比自己手工写的string pools,jdk的string pooling使用内存极少(-Xmx1280M支持12.72M字符串,自己写的只有不到1/5)。
       Jdk8中默认pool size调到25-50K。


socket连接时的timeout:通过Socket.connect(SocketAddress endpoint, int timeout)设置
socket读写时的timeout:通过Socket.setSoTimeout(int timeout)设置


Java使用自动装箱和自动拆箱机制,节省了常用数值的内存开销和创建对象的开销,提高了效率。
Java基本数据类型对应的包装类型的自动装箱池大小:
       Byte,Short,Long对应的是-128~127
       Character对应的是0~127
       Float和Double没有自动装箱池
0 0
原创粉丝点击