php模板建站,深圳专业app网站开发,wordpress 评论贴图,常州建站服务在使用Java编程语言时#xff0c;我们将继续讨论与建议的实践有关的系列文章#xff0c;我们将讨论并演示如何将对象序列化用于高性能应用程序。 所有讨论的主题均基于用例#xff0c;这些用例来自于电信行业的关键任务超高性能生产系统的开发。 在阅读本文的每个部分之前… 在使用Java编程语言时我们将继续讨论与建议的实践有关的系列文章我们将讨论并演示如何将对象序列化用于高性能应用程序。 所有讨论的主题均基于用例这些用例来自于电信行业的关键任务超高性能生产系统的开发。 在阅读本文的每个部分之前强烈建议您参考相关的Java API文档以获取详细信息和代码示例。 所有测试均针对具有以下特征的Sony Vaio进行 系统openSUSE 11.1x86_64 处理器CPUIntelRCoreTM2 Duo CPU T6670 2.20GHz 处理器速度1,200.00 MHz 总内存RAM2.8 GB JavaOpenJDK 1.6.0_0 64位 应用以下测试配置 并发工作者线程200 每个工作人员重复测试的次数1000 整体测试次数100 高性能序列化 序列化是将对象转换为字节流的过程。 然后可以通过套接字发送该流将其存储到文件和/或数据库中或者直接按原样对其进行操作。 在本文中我们不打算对序列化机制进行深入的描述有许多文章提供了这种信息。 这里将讨论的是我们利用序列化以实现高性能结果的主张。 序列化的三个主要性能问题是 序列化是一种递归算法。 从单个对象开始通过实例变量可以从该对象访问的所有对象也被序列化。 默认行为很容易导致不必要的序列化开销 序列化和反序列化都需要序列化机制来发现有关其序列化实例的信息。 使用默认的序列化机制将使用反射来发现所有字段值。 此外如果您未明确设置“ serialVersionUID”类属性则序列化机制必须对其进行计算。 这涉及遍历所有字段和方法以生成哈希。 上述过程可能很慢 使用默认的序列化机制所有序列化类描述信息都包含在流中例如 所有可序列化超类的描述 类本身的描述 与类的特定实例相关联的实例数据 要解决上述性能问题可以改用外部化。 这两种方法之间的主要区别在于序列化将所有可序列化超类的类描述以及与该实例相关联的信息当被视为每个单独的超类的实例写出。 另一方面外部化将写出类的标识类的名称和适当的“ serialVersionUID”类属性以及超类结构以及有关类层次结构的所有信息。 换句话说它存储所有元数据但仅写出本地实例信息。 简而言之外部化几乎消除了序列化机制使用的所有反射调用使您可以完全控制编组和解组算法从而显着提高性能。 当然外部化效率是有代价的。 由于从类定义中自动提取了元数据因此默认的序列化机制可适应应用程序更改。 另一方面外部化不是很灵活需要您在更改类定义时重写编组和解组代码。 以下是有关如何将外部化用于高性能应用程序的简短演示。 我们将从提供“ Employee”对象开始执行序列化和反序列化操作。 将使用两种类型的“ Employee”对象。 一种适合标准序列化操作另一种经过修改以便可以外部化。 以下是“雇员”对象的第一种味道 package com.javacodegeeks.test;import java.io.Serializable;
import java.util.Date;
import java.util.List;public class Employee implements Serializable {private static final long serialVersionUID 3657773293974543890L;private String firstName;private String lastName;private String socialSecurityNumber;private String department;private String position;private Date hireDate;private Double salary;private Employee supervisor;private Liststring phoneNumbers;public Employee() {}public Employee(String firstName, String lastName,String socialSecurityNumber, String department, String position,Date hireDate, Double salary) {this.firstName firstName;this.lastName lastName;this.socialSecurityNumber socialSecurityNumber;this.department department;this.position position;this.hireDate hireDate;this.salary salary;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName lastName;}public String getSocialSecurityNumber() {return socialSecurityNumber;}public void setSocialSecurityNumber(String socialSecurityNumber) {this.socialSecurityNumber socialSecurityNumber;}public String getDepartment() {return department;}public void setDepartment(String department) {this.department department;}public String getPosition() {return position;}public void setPosition(String position) {this.position position;}public Date getHireDate() {return hireDate;}public void setHireDate(Date hireDate) {this.hireDate hireDate;}public Double getSalary() {return salary;}public void setSalary(Double salary) {this.salary salary;}public Employee getSupervisor() {return supervisor;}public void setSupervisor(Employee supervisor) {this.supervisor supervisor;}public Liststring getPhoneNumbers() {return phoneNumbers;}public void setPhoneNumbers(Liststring phoneNumbers) {this.phoneNumbers phoneNumbers;}} 这里要注意的事情 我们假设以下字段是必填字段 “名字” “姓” “社会安全号码” “部” “位置” “雇用日期” “薪水” 以下是“雇员”对象的第二种风味 package com.javacodegeeks.test;import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Arrays;
import java.util.Date;
import java.util.List;public class Employee implements Externalizable {private String firstName;private String lastName;private String socialSecurityNumber;private String department;private String position;private Date hireDate;private Double salary;private Employee supervisor;private Liststring phoneNumbers;public Employee() {}public Employee(String firstName, String lastName,String socialSecurityNumber, String department, String position,Date hireDate, Double salary) {this.firstName firstName;this.lastName lastName;this.socialSecurityNumber socialSecurityNumber;this.department department;this.position position;this.hireDate hireDate;this.salary salary;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName lastName;}public String getSocialSecurityNumber() {return socialSecurityNumber;}public void setSocialSecurityNumber(String socialSecurityNumber) {this.socialSecurityNumber socialSecurityNumber;}public String getDepartment() {return department;}public void setDepartment(String department) {this.department department;}public String getPosition() {return position;}public void setPosition(String position) {this.position position;}public Date getHireDate() {return hireDate;}public void setHireDate(Date hireDate) {this.hireDate hireDate;}public Double getSalary() {return salary;}public void setSalary(Double salary) {this.salary salary;}public Employee getSupervisor() {return supervisor;}public void setSupervisor(Employee supervisor) {this.supervisor supervisor;}public Liststring getPhoneNumbers() {return phoneNumbers;}public void setPhoneNumbers(Liststring phoneNumbers) {this.phoneNumbers phoneNumbers;}public void readExternal(ObjectInput objectInput) throws IOException,ClassNotFoundException {this.firstName objectInput.readUTF();this.lastName objectInput.readUTF();this.socialSecurityNumber objectInput.readUTF();this.department objectInput.readUTF();this.position objectInput.readUTF();this.hireDate new Date(objectInput.readLong());this.salary objectInput.readDouble();int attributeCount objectInput.read();byte[] attributes new byte[attributeCount];objectInput.readFully(attributes);for (int i 0; i attributeCount; i) {byte attribute attributes[i];switch (attribute) {case (byte) 0:this.supervisor (Employee) objectInput.readObject();break;case (byte) 1:this.phoneNumbers Arrays.asList(objectInput.readUTF().split(;));break;}}}public void writeExternal(ObjectOutput objectOutput) throws IOException {objectOutput.writeUTF(firstName);objectOutput.writeUTF(lastName);objectOutput.writeUTF(socialSecurityNumber);objectOutput.writeUTF(department);objectOutput.writeUTF(position);objectOutput.writeLong(hireDate.getTime());objectOutput.writeDouble(salary);byte[] attributeFlags new byte[2];int attributeCount 0;if (supervisor ! null) {attributeFlags[0] (byte) 1;attributeCount;}if (phoneNumbers ! null !phoneNumbers.isEmpty()) {attributeFlags[1] (byte) 1;attributeCount;}objectOutput.write(attributeCount);byte[] attributes new byte[attributeCount];int j attributeCount;for (int i 0; i 2; i)if (attributeFlags[i] (byte) 1) {j--;attributes[j] (byte) i;}objectOutput.write(attributes);for (int i 0; i attributeCount; i) {byte attribute attributes[i];switch (attribute) {case (byte) 0:objectOutput.writeObject(supervisor);break;case (byte) 1:StringBuilder rowPhoneNumbers new StringBuilder();for(int k 0; k phoneNumbers.size(); k)rowPhoneNumbers.append(phoneNumbers.get(k) ;);rowPhoneNumbers.deleteCharAt(rowPhoneNumbers.lastIndexOf(;));objectOutput.writeUTF(rowPhoneNumbers.toString());break;}}}
} 这里要注意的事情 我们实现了“ writeExternal”方法来编组“ Employee”对象。 所有必填字段都写入流 对于“ hireDate”字段我们仅写入此Date对象表示的毫秒数。 假设demarshaller将使用与marshaller相同的时区毫秒值就是我们正确反序列化“ hireDate”字段所需的所有信息。 请记住我们可以使用“ objectOutput.writeObjecthireDate”操作来序列化整个“ hireDate”对象。 在这种情况下默认的序列化机制将导致结果流的速度下降和大小增加 所有非强制性字段“ supervisor”和“ phoneNumbers”只有在它们具有实际非空值时才被写入流中。 为了实现此功能我们使用“ attributeFlags”和“ attributes”字节数组。 “ attributeFlags”数组的每个位置代表一个非强制性字段并保留一个“标记”指示特定字段是否具有值。 我们检查每个非必填字段并使用相应的标记填充“ attributeFlags”字节数组。 “属性”字节数组指示必须通过“位置”写入流中的实际非必需字段。 例如如果“ supervisor”和“ phoneNumbers”非必填字段均具有实际值则“ attributeFlags”字节数组应为[1,1]而“ attributes”字节数组应为[0,1]。 如果仅“ phoneNumbers”非强制字段具有非空值则“ attributeFlags”字节数组应为[0,1]而“ attributes”字节数组应为[1]。 通过使用上述算法我们可以为结果流实现最小的尺寸占用。 为了正确地反序列化“ Employee”对象的非必需参数我们必须仅将以下信息写入流 将要写入的非强制参数的总数又称“属性”字节数组大小–供编组者解析 “属性”字节数组供编组员正确分配字段值 实际非强制性参数值 对于“ phoneNumbers”字段我们构造并将其内容的String表示形式写入流中。 或者我们可以使用“ objectOutput.writeObjectphoneNumbers”操作序列化整个“ phoneNumbers”对象。 在这种情况下默认的序列化机制将导致结果流的速度下降和大小增加 我们实现了“ readExternal”方法来对“ Employee”对象进行编组。 所有必填字段都将写入流中。 对于非必填字段demarshaller根据上述协议分配适当的字段值 对于序列化和反序列化过程我们使用了以下四个功能。 这些功能有两种形式。 第一对适用于序列化和反序列化Externalizable对象实例而第二对适用于序列化和反序列化Serializable对象实例。 public static byte[][] serializeObject(Externalizable object) throws Exception {ByteArrayOutputStream baos null;ObjectOutputStream oos null;byte[][] res new byte[2][];try {baos new ByteArrayOutputStream();oos new ObjectOutputStream(baos);object.writeExternal(oos);oos.flush();res[0] object.getClass().getName().getBytes();res[1] baos.toByteArray();} catch (Exception ex) {throw ex;} finally {try {if(oos ! null)oos.close();} catch (Exception e) {e.printStackTrace();}}return res;}public static Externalizable deserializeObject(byte[][] rowObject) throws Exception {ObjectInputStream ois null;String objectClassName null;Externalizable res null;try {objectClassName new String(rowObject[0]);byte[] objectBytes rowObject[1];ois new ObjectInputStream(new ByteArrayInputStream(objectBytes));Class objectClass Class.forName(objectClassName);res (Externalizable) objectClass.newInstance();res.readExternal(ois);} catch (Exception ex) {throw ex;} finally {try {if(ois ! null)ois.close();} catch (Exception e) {e.printStackTrace();}}return res;}public static byte[] serializeObject(Serializable object) throws Exception {ByteArrayOutputStream baos null;ObjectOutputStream oos null;byte[] res null;try {baos new ByteArrayOutputStream();oos new ObjectOutputStream(baos);oos.writeObject(object);oos.flush();res baos.toByteArray();} catch (Exception ex) {throw ex;} finally {try {if(oos ! null)oos.close();} catch (Exception e) {e.printStackTrace();}}return res;}public static Serializable deserializeObject(byte[] rowObject) throws Exception {ObjectInputStream ois null;Serializable res null;try {ois new ObjectInputStream(new ByteArrayInputStream(rowObject));res (Serializable) ois.readObject();} catch (Exception ex) {throw ex;} finally {try {if(ois ! null)ois.close();} catch (Exception e) {e.printStackTrace();}}return res;} 下面我们展示了上述两种方法之间的性能比较表 横轴表示测试运行的次数纵轴表示每次测试运行的每秒平均事务数TPS。 因此较高的值更好。 如您所见与普通的Serializable方法相比使用Externalizable方法可以在序列化和反序列化时获得出色的性能提升。 最后我们必须指出我们执行了测试为“ Employee”对象的所有非必填字段提供了值。 如果在相同方法之间进行比较时不使用所有非强制性参数并且最重要的是在Externalizable和Serializable方法之间进行交叉比较时您应该期望获得更高的性能提升。 编码愉快 贾斯汀 相关文章 Java最佳实践–多线程环境中的DateFormat Java最佳实践– Vector vs ArrayList vs HashSet Java最佳实践–字符串性能和精确字符串匹配 Java最佳实践–队列之战和链接的ConcurrentHashMap Java最佳实践– Char到Byte和Byte到Char的转换 翻译自: https://www.javacodegeeks.com/2010/07/java-best-practices-high-performance.html