Kryo序列化,kryo序列化原理

  Kryo序列化,kryo序列化原理

  00-1010 Kryo的基本用法序列化概述Kryo序列化程序对象的注册引用线程不安全线程本地Kryo解决线程不安全对象池Kryo解决线程不安全摘要

  00-1010KRYO是一个快速的序列化/反序列化工具,它依赖于字节码生成机制(底层使用ASM库),所以在序列化速度上有一定的优势,但正因为如此,它的使用只能局限于基于JVM的语言。

  与Hessian类似,Kryo序列化的结果是它自己的定制和独特的格式。因为序列化的结果是二进制的,也就是byte[],所以像Redis这种可以存储二进制数据的存储引擎可以直接存储Kryo序列化的数据。当然,你也可以选择将其转换成字符串,存储在其他存储引擎中(性能有所损失)。

  00-1010介绍了这么多。接下来,我们来看看Kryo的基本用法。其实对于序列化框架来说,API基本都是一样的。毕竟,参与和退出通常是确定性的(要序列化的对象/序列化的结果)。在使用Kryo之前,我们需要引入相应的依赖关系。

  依赖性groupIdcom.esotericsoftware/groupId artifactIdkryo/artifactId版本5 . 2 . 0/版本/依赖性基本使用如下所示:

  导入com . esoteric software . kryo . kryo;导入com . esoteric software . kryo . io . input;导入com . esoteric software . kryo . io . output;导入Java . io . *;公共类hello Kryo { static public void main(String[]args)抛出异常{ Kryo Kryo=new Kryo();kryo . register(some class . class);some class object=new some class();object.value=你好Kryo!;Output Output=new Output(new file Output stream( file . bin ));kryo.writeObject(输出,对象);output . close();Input input=new Input(新文件输入流( file . bin ));some class object 2=kryo . read object(input,some class . class);input . close();system . out . println(object 2 . value);}静态公共类SomeClass { String value} } } } Kryo类自动执行序列化。输出和输入类负责处理缓冲区字节并将它们写入流中。如果序列化前后类的字段不一致,反序列化将失败。

  00-1010作为一个灵活的序列化框架,Kryo并不关心数据的读写。作为开发者,你可以随意使用Kryo提供的那些开箱即用的序列化器。

  与许多其他序列化框架一样,Kryo提供了一种注册的方法来序列化对象类,以提高性能并减少序列化结果的数量。在注册时,将为序列化的类生成int ID,然后在序列化过程中,该类型将由int ID唯一标识。

  注册的方式如下:

  kryo . register(some class . class);或者

  kryo.register(SomeClass.class,1);可以显式指定注册类的int ID,但ID必须大于或等于0。如果没有,内部会以int的形式维护一个有序的int ID生成。

  

目录

Kryo支持多种序列化器,通过源代码我们也能看出一二。

 

  xt-align:center">

  具体可参考

  虽然 Kryo 提供的序列化器可以读写大多数对象,但开发者也可以轻松的制定自己的序列化器。篇幅限制,这里就不展开说明了,仅以默认的序列化器为例。

  

 

  

对象引用

在新版本的 Kryo 中,默认情况下是不启用对象引用的。这意味着如果一个对象多次出现在一个对象图中,它将被多次写入,并将被反序列化为多个不同的对象。

 

  举个例子,当开启了引用属性,每个对象第一次出现在对象图中,会在记录时写入一个 varint,用于标记。当此后有同一对象出现时,只会记录一个 varint,以此达到节省空间的目标。此举虽然会节省序列化空间,但是是一种用时间换空间的做法,会影响序列化的性能,这是因为在写入/读取对象时都需要进行追踪。

  开发者可以使用 kryo 自带的 setReferences 方法来决定是否启用 Kryo 的引用功能。

  

public class KryoReferenceDemo { public static void main(String[] args) throws FileNotFoundException { Kryo kryo = new Kryo(); kryo.register(User.class); kryo.register(Account.class); User user = new User(); user.setUsername("alvin"); Account account = new Account(); account.setAccountNo("10000"); // 循环引用 user.setAccount(account); account.setUser(user); // 这里需要设置为true,才不会报错 kryo.setReferences(true); Output output = new Output(new FileOutputStream("kryoreference.bin")); kryo.writeObject(output, user); output.close(); Input input = new Input(new FileInputStream("kryoreference.bin")); User object2 = kryo.readObject(input, User.class); input.close(); System.out.println(object2.getUsername()); System.out.println(object2.getAccount().getAccountNo()); } public static class User { private String username; private Account account; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Account getAccount() { return account; } public void setAccount(Account account) { this.account = account; } } public static class Account { private String accountNo; private String amount; private User user; public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public String getAmount() { return amount; } public void setAmount(String amount) { this.amount = amount; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }}

如果序列化前的setReferences(false), 后面设置setReferences(true)进行反序列化,会失败。

 

  

 

  

线程不安全

Kryo 不是线程安全的。每个线程都应该有自己的 Kryo 对象、输入和输出实例。

 

  因此在多线程环境中,可以考虑使用 ThreadLocal 或者对象池来保证线程安全性。

  

 

  

ThreadLocal + Kryo 解决线程不安全

ThreadLocal 是一种典型的牺牲空间来换取并发安全的方式,它会为每个线程都单独创建本线程专用的 kryo 对象。对于每条线程的每个 kryo 对象来说,都是顺序执行的,因此天然避免了并发安全问题。创建方法如下:

 

  

static private final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() {  protected Kryo initialValue() {     Kryo kryo = new Kryo();     // 在此处配置kryo对象的使用示例,如循环引用等     return kryo;  };};Kryo kryo = kryos.get();

之后,仅需要通过 kryos.get() 方法从线程上下文中取出对象即可使用。

 

  

 

  

对象池 + Kryo 解决线程不安全

「池」是一种非常重要的编程思想,连接池、线程池、对象池等都是

 

  「复用」思想的体现,通过将创建的对象保存在某一个容器中,以便后续反复使用,避免创建、销毁的产生的性能损耗,以此达到提升整体性能的作用。

  Kryo 对象池原理也是如此。Kryo 框架自带了对象池的实现,整个使用过程不外乎创建池、从池中获取对象、归还对象三步,以下为代码实例。

  

// Pool constructor arguments: thread safe, soft references, maximum capacityPool<Kryo> kryoPool = new Pool<Kryo>(true, false, 8) {  protected Kryo create () {     Kryo kryo = new Kryo();     // Kryo 配置     return kryo;  }};// 获取池中的Kryo对象Kryo kryo = kryoPool.obtain();// 将kryo对象归还到池中kryoPool.free(kryo);

创建 Kryo 池时需要传入三个参数,其中第一个参数用于指定是否在 Pool 内部使用同步,如果指定为 true,则允许被多个线程并发访问。第三个参数适用于指定对象池的大小的,这两个参数较容易理解,因此重点来说一下第二个参数。

 

  如果将第二个参数设置为 true,Kryo 池将会使用 java.lang.ref.SoftReference 来存储对象。这允许池中的对象在 JVM 的内存压力大时被垃圾回收。Pool clean 会删除所有对象已经被垃圾回收的软引用。当没有设置最大容量时,这可以减少池的大小。当池子有最大容量时,没有必要调用 clean,因为如果达到了最大容量,Pool free 会尝试删除一个空引用。

  创建完 Kryo 池后,使用 kryo 就变得异常简单了,只需调用 kryoPool.obtain() 方法即可,使用完毕后再调用 kryoPool.free(kryo) 归还对象,就完成了一次完整的租赁使用。

  理论上,只要对象池大小评估得当,就能在占用极小内存空间的情况下完美解决并发安全问题。如果想要封装一个 Kryo 的序列化方法,可以参考如下的代码

  

public static byte[] serialize(Object obj) {   Kryo kryo = kryoPool.obtain();   // 使用 Output 对象池会导致序列化重复的错误(getBuffer返回了Output对象的buffer引用)   try (Output opt = new Output(1024, -1)) {       kryo.writeClassAndObject(opt, obj);       opt.flush();       return opt.getBuffer();  }finally {       kryoPool.free(kryo);  }}

 

  

小结

相较于 JDK 自带的序列化方式,Kryo 的性能更快,并且由于 Kryo 允许多引用和循环引用,在存储开销上也更小。只不过,虽然 Kryo 拥有非常好的性能,但其自身却舍去了很多特性,例如线程安全、对序列化对象的字段修改等。虽然这些弊端可以通过 Kryo 良好的扩展性得到一定的满足,但是对于开发者来说仍然具有一定的上手难度,不过这并不能影响其在 Java 中的地位。

 

  到此这篇关于Java高性能序列化工具Kryo详情的文章就介绍到这了,更多相关 Java Kryo序列化内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • json序列化和反序列化方法,json反序列化失败是什么意思
  • win2003r2 序列号,windowsserver2003序列号
  • win2003r2 序列号,windowsserver2003序列号,win2003 序列号大全 windows2003 sp2经测试可用的序列号(标准版与企业版)
  • ,,光碟工具 Alcohol 120% v1.9.6.4719 下载(附序列号注册码)
  • ,,xp序列号大全可通过正版验证的XP序列号
  • java中serialversionuid生成,java serialversionuid的值区别,java序列化和serialVersionUID的使用方法实例
  • ,,Python中利用LSTM模型进行时间序列预测分析的实现
  • 时间序列adf检验怎么判断平稳性,
  • python时间序列模型,python时间序列预测代码
  • 用python实现ARIMA时间序列预测实例,python时间序列预测的方法
  • python时间序列分析模块,用python实现ARIMA时间序列预测实例
  • 时间序列模型用于哪种预测,时间序列预测模型实验报告
  • 时间序列分析难不难,时间序列分析问题
  • python最简单的时间序列预测,python 时间序列模型
  • 基于lstm的时间序列预测,基于cnn的时间序列预测模型
  • 留言与评论(共有 条评论)
       
    验证码: