java高性能序列化_Java最佳实践–高性能序列化

java高性能序列化

在使用Java编程语言时,我们将继续讨论与建议的实践有关的系列文章,我们将讨论并演示如何将对象序列化用于高性能应用程序。

所有讨论的主题均基于用例,这些用例源于电信行业关键任务超高性能生产系统的开发。

在阅读本文的每个部分之前,强烈建议您参考相关的Java API文档以获取详细信息和代码示例。

所有测试均针对具有以下特征的Sony Vaio进行:

  • 系统:openSUSE 11.1(x86_64)
  • 处理器(CPU):Intel(R)Core(TM)2 Duo CPU T6670 @ 2.20GHz
  • 处理器速度:1,200.00 MHz
  • 总内存(RAM):2.8 GB
  • Java:OpenJDK 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 List<string> 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 List<string> getPhoneNumbers() {return phoneNumbers;}public void setPhoneNumbers(List<string> 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 List<string> 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 List<string> getPhoneNumbers() {return phoneNumbers;}public void setPhoneNumbers(List<string> 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”方法。 所有必填字段都写入流
  • 对于“ hireDate”字段,我们仅写入此Date对象表示的毫秒数。 假设demarshaller将使用与marshaller相同的时区,那么毫秒值就是我们要正确反序列化“ hireDate”字段所需的所有信息。 请记住,我们可以使用“ objectOutput.writeObject(hireDate)”操作来序列化整个“ hireDate”对象。 在这种情况下,默认的序列化机制将导致结果流的速度下降和大小增加
  • 所有非强制性字段(“ supervisor”和“ phoneNumbers”)只有在具有实际值(非null)时才被写入流中。 为了实现此功能,我们使用“ attributeFlags”和“ attributes”字节数组。 “ attributeFlags”数组的每个位置代表一个非强制性字段,并保留一个“标记”,指示特定字段是否具有值。 我们检查每个非必填字段,并使用相应的标记填充“ attributeFlags”字节数组。 “属性”字节数组指示必须通过“位置”写入流中的实际非必需字段。 例如,如果“ supervisor”和“ phoneNumbers”非必填字段均具有实际值,则“ attributeFlags”字节数组应为[1,1],而“ attributes”字节数组应为[0,1]。 如果只有“ phoneNumbers”非必需字段具有非空值,则“ attributeFlags”字节数组应为[0,1],而“ attributes”字节数组应为[1]。 通过使用上述算法,我们可以为生成的流实现最小的尺寸占用。 为了正确地反序列化“ Employee”对象的非必需参数,我们必须仅将以下信息写入流:
    • 将要写入的非强制性参数的总数(又称“属性”字节数组大小-供编组者解析)
    • “属性”字节数组(供编组员正确分配字段值)
    • 实际非强制性参数值
  • 对于“ phoneNumbers”字段,我们构造并将其内容的String表示形式写入流中。 或者,我们可以使用“ objectOutput.writeObject(phoneNumbers)”操作来序列化整个“ 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方法相比,使用Serializable方法可以在序列化和反序列化时获得更高的性能。

最后,我们必须指出我们执行了测试,为“ 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

java高性能序列化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux进程属主6,20150917 Linux进程查看与管理以及作业管理

第一、基础知识MBR引导--内核--内核程序--》协调其它程序一般内核运行在硬件之上&#xff0c;各应用也在硬件之前1)OS的基本功能&#xff1a;文件系统、网络功能、进程管理、内存管理、驱动程序、安全功能以上为通用目的设置的程序。&#xff0c;程序指令数据&#xff0c;程序运…

在javaweb中通过servlet类和普通类读取资源文件

javaweb有两种方式读取资源文件 在Servlet中读取&#xff0c;可以使用servletContext&#xff0c;servletContext可以拿到web所有的资源文件&#xff0c;然后随便读&#xff0c;但是这种方法不常用&#xff0c;尽量少在Servlet中读取资源文件 在普通Java类中&#xff08;DAO中&…

数学图形(1.43)贝壳形曲线与鱼形曲线

贝壳形曲线 #http://curvebank.calstatela.edu/naturalcurves/slide7.jpgvertices 12000t from 0 to (2*PI)r 10*(0.7 2.6*cos(t) 1.3*pow(sin(90*t), 3))x r*sin(t) y r*cos(t) 鱼形曲线 #http://www.2dcurves.com/quartic/quarticfi.html vertices 1000 t from 0 to…

linux下编译ios,为iOS安装OpenCV

一&#xff0c;要求CMake 2.8.8 或者更高Xcode 4.2 或者更新二&#xff0c;从Git库取得最新的 OpenCV使用 git 客户端从 http://github.com/itseez/opencv clone Open 库。在 max os x 下&#xff0c;可以通过以下命令行完成cd ~/git clone https://github.com/Itseez/opencv…

学习使用资源文件[11] - DLL 中的资源文件

本例将把一张 bmp 图片, 以资源文件的方式嵌入 dll, 然后再调用.第一步: 建一个 DLL 工程, 如图:然后保存, 我这里使用的名称都是默认的.第二步: 建一个资源原文件, 如图:编辑内容如下(路径中的文件一定要存在):img1 BITMAP "c:\temp\test.bmp"然后, 取个名(后缀须是…

linux 自动安装 yum,LINUX6安装YUM仓库和实现开机自动挂载

# LINUX6安装YUM仓库和实现开机自动挂载---------------------------------安装环境-------------------------------Redhat6镜像文件&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1DKH6adbrsipM-cTzH-wBgA 百度网盘 密码是hxcbVmware Workstation虚拟机工具&#x…

.NET Framework 4.0源代码

原文出处&#xff1a;http://blogs.microsoft.co.il/blogs/arik/archive/2010/07/12/step-into-net-framework-4-0-source-code.aspx 本文将向你展示如何配置Visual Studio 2010逐语句执行.NET Framework 4.0源代码。 为啥? 因为很酷。 因为能帮助调试。 你不仅能看到源代码…

linux blender骨骼绑定,在Linux系统中安装开源3D创建套件Blender的方法

Blender是免费的开源3D创建套件&#xff0c;它可在Linux系统中安装&#xff0c;可使用snap或flatpak命令安装Blender。简介Blender也称为开源3D建模软件&#xff0c;支持整个3D管道&#xff0c;建模&#xff0c;装配&#xff0c;动画&#xff0c;模拟&#xff0c;渲染&#xff…

配置源码管理工具(2)

源码管理是开发中最重要的事情之一&#xff0c;在vs.net里我们通常采用vss进行版本控制&#xff0c;在Eclipse里看帖子说用svn的比例很大&#xff0c;和IDE的集成性也很好。 1&#xff1a;服务器部署 下载地址是&#xff1a;http://subversion.apache.org/packages.html 下载的…

编写下载服务器。 第六部分:描述您发送的内容(内容类型等)

就HTTP而言&#xff0c;客户端下载的只是一堆字节。 但是&#xff0c;客户真的很想知道如何解释这些字节。 它是图像吗&#xff1f; 或者也许是ZIP文件&#xff1f; 本系列的最后一部分描述了如何向客户端提示她下载的内容。 设置 内容类型描述了要返回的资源的MIME类型 。 此…

ruby中的self

self&#xff0c;自己&#xff0c;在ruby中表示当前对象或默认对象。程序执行的任一时刻&#xff0c;有且仅有一个self。 1.谁成为self&#xff0c;在什么位置成为self&#xff1f; 要知道哪个对象是self&#xff0c;就必须知道当前的上下文。上下文主要有顶层上下文&#xff0…

二手宏碁上网本装linux,Acer国内20日首发“上网本” 放弃Linux使用XP

据相关媒体报道 8月20日将在国内正式推出XP系统版的8.9英寸超便携笔记本电脑Aspire One&#xff0c;放弃使用Linux系统&#xff0c;硬件配置方面&#xff0c;除了依然采用英特尔Atom处理器之外&#xff0c;推出120GB传统硬盘和SSD两个版本。其中&#xff0c;XP系统 120G传统硬盘…

免费WiFi,仅仅为好久没联系的你们

昨日&#xff0c;认识五年的朋友搬来与我一起住了&#xff0c;说不上来&#xff0c;没有激动&#xff0c;仅仅是突然感觉生活又多了一点生机。兴致上来&#xff0c;晚上立马联系了已经近四个月没有联系的好友&#xff0c;才知道他们的生活也因这几个月发生了翻天覆地的变化。究…

五猴分桃c语言课程设计,c语言程序设计五猴分桃问题实验报告.doc

c语言程序设计五猴分桃问题实验报告.doc 课程设计报告学院、系&#xff1a;吉林大学珠海学院计算机科学与技术系专业名称&#xff1a;软件工程课程设计科目C语言程序课程设计所在班级&#xff1a;10班学生学号&#xff1a;04121010学生姓名&#xff1a;赵学文指导教师&#xff…

c语言100以内奇数的和为多少,编写C#程序,计算100以内所有奇数的和。谢谢了,大神帮忙啊...

编写C#程序&#xff0c;计算100以内所有奇数的和。谢谢了&#xff0c;大神帮忙啊以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;编写C#程序&#xff0c;计算100以内所有奇数的和。谢谢了&am…

监控系统的多协议直播(RTSP RTMP HTTP Live Streaming)

监控系统的多协议直播&#xff08;RTSP RTMP HTTP Live Streaming) 转载于:https://www.cnblogs.com/cl1024cl/p/6204791.html

阿里媒体转码公共参数_Xuggler教程:转码和媒体修改

阿里媒体转码公共参数注意&#xff1a;这是我们的“ Xuggler开发教程 ”系列的一部分。 在上一教程中&#xff0c;我对视频处理Xuggler进行了简短介绍 。 在这一部分中&#xff0c;我们将看到Xuggler和FFmpeg提供的一些更令人兴奋的功能&#xff0c;例如视频转码和媒体修改。 别…

52单片机iic读写c语言,如何52单片机的I2C读写24C08程序问题排查修改

------波形在一楼isoimg2130老师提供在单片机正常运行的程序&#xff1a;#include "reg52.h"#include "intrins.h"typedef unsigned char u8;sbit SCLP2^1; //I2C 时钟sbit SDAP2^2; …

qfp封装能够linux,QFP、PQFP、LQFP、TQFP封装形式及PCB详解

问题&#xff1a;画PCB时&#xff0c;会发现很多的集成电路都是QFP封装&#xff0c;比如很多的单片机都有这种封装。各个器件商会在自己的数据手册中说明他的器件是QFP&#xff0c;LQFP或TQFP&#xff0c;然后&#xff0c;有的给出封装尺寸图&#xff0c;有的则不给。那么&…

dede文章列表加上序号效果

dede文章列表加上序号效果 css代码部分 <style type"text/css"> <!-- .downtop { FLOAT: left; OVERFLOW: hidden; WIDTH: 218px; HEIGHT: 278px } .downtop UL.text { MARGIN: 0px 10px; WIDTH: 198px; PADDING-TOP: 5px } .downtop UL.text LI { WIDTH: 1…