网上有很多资料说 Kryo 只能在 Java 上使用,这点是不对的,事实上除 Java 外,Scala 和 Kotlin 这些基于 JVM 的语言同样可以使用 Kryo 实现序列化。

1.使用方法

(1)添加kyro依赖

<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.2.0</version>
</dependency>

(2)基本使用概况

Kryo 类会自动执行序列化。Output 类和 Input 类负责处理缓冲字节,并写入到流中。

public class HelloKryo {
static public void main(String[] args) throws Exception {
Kryo kryo = new Kryo();
kryo.register(SomeClass.class); SomeClass object = new SomeClass();
object.value = "Hello Kryo!"; Output output = new Output(new FileOutputStream("file.bin"));
kryo.writeObject(output, object);
output.close(); Input input = new Input(new FileInputStream("file.bin"));
SomeClass object2 = kryo.readObject(input, SomeClass.class);
input.close();
System.out.println(object2.value);
} static public class SomeClass {
String value;
}
}

(3)Kyro注册

和很多其他的序列化框架一样,Kryo 为了提供性能减小序列化结果体积,提供注册的序列化对象类的方式。在注册时,会为该序列化类生成 int ID,后续在序列化时使用 int ID 唯一标识该类型。注册的方式如下:



或者



可以明确指定注册类的 int ID,但是该 ID 必须大于等于 0。如果不提供,内部将会使用 int++的方式维护一个有序的 int ID 生成。

2.线程不安全

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

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

ThreadLocal解决线程不安全

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 框架自带了对象池的实现,整个使用过程不外乎创建池、从池中获取对象、归还对象三步,以下为代码实例。

// Pool constructor arguments: thread safe, soft references, maximum capacity
Pool<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);

参数分析:

第一个参数用于指定是否在 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);
}
}

3.小结

相较于 JDK 自带的序列化方式,Kryo 的性能更快,并且由于 Kryo 允许多引用和循环引用,在存储开销上也更小。

只不过,虽然 Kryo 拥有非常好的性能,但其自身却舍去了很多特性,例如线程安全、对序列化对象的字段修改等。虽然这些弊端可以通过 Kryo 良好的扩展性得到一定的满足,但是对于开发者来说仍然具有一定的上手难度,不过这并不能影响其在 Java 中的地位。

序列化框架-Kyro简述的更多相关文章

  1. 常见的序列化框架及Protobuf序列化原理

    原文链接:https://www.jianshu.com/p/657fbf347934 https://www.cnblogs.com/javazhiyin/p/11375553.html https ...

  2. 5.3.4 Hadoop序列化框架

    序列化框架 除了writable实现序列化之外,只要实现让类型和二进制流相互转换,都可以作为hadoop的序列化类型,为此Hadoop提供了一个序列化框架接口,他们在org.apache.hadoop ...

  3. Mapreduce之序列化框架(转自http://blog.csdn.net/lastsweetop/article/details/9376495)

    框架简介 MapReduce仅仅可以支持Writable做key,value吗?答案是否定的.事实上,一切类型都是支持的,只需满足一个小小的条件:每个类型是以二进制流的形式传输.为此Hadoop提供了 ...

  4. [java]序列化框架性能对比(kryo、hessian、java、protostuff)

    序列化框架性能对比(kryo.hessian.java.protostuff) 简介:   优点 缺点 Kryo 速度快,序列化后体积小 跨语言支持较复杂 Hessian 默认支持跨语言 较慢 Pro ...

  5. 二进制序列化框架easypack发布啦!

    简介 easypack是基于boost.serialization的二进制序列化框架,使用极其方便. Examples 基本类型 int age = 20; std::string name = &q ...

  6. Java序列化框架性能比較

    博客: http://colobu.com jvm-serializers提供了一个非常好的比較各种Java序列化的的測试套件. 它罗列了各种序列化框架. 能够自己主动生成測试报告. 我在AWS c3 ...

  7. 序列化战争:主流序列化框架Benchmark

    序列化战争:主流序列化框架Benchmark GitHub上有这样一个关于序列化的Benchmark,被好多文章引用.但这个项目考虑到完整性,代码有些复杂.为了个人学习,自己实现了个简单的Benchm ...

  8. 一些常用Java序列化框架的比较

    概念 序列化:将Java对象转化为字节数组 反序列化:将字节数组转化为Java对象 在RPC应用中,进行跨进程远程调用的时候,需要使用特定的序列化技术,需要对进行网络传输的对象进行序列化和反序列化. ...

  9. java基础---->序列化框架arvo的使用

    这里面我们介绍一下序列化框架arvo的使用,在kafka中使用的就是这个. arvo的使用 一.需要通过插件生成Model类方式 一.生成我们的数据模型User.java 我们在resources里面 ...

  10. hadoop深入研究:(十三)——序列化框架

    hadoop深入研究:(十三)--序列化框架 Mapreduce之序列化框架(转自http://blog.csdn.net/lastsweetop/article/details/9376495) 框 ...

随机推荐

  1. app自动化测试环境安装

    一.环境依赖 app自动化测试环境如下: appium服务 第三方库appium-python-client 手机或模拟器 java环境jdk1.8 android环境 二.appium服务安装 1. ...

  2. .NET Core C#系列之XiaoFeng.Data.IQueryableX ORM框架

    ​ 当前对象操作数据库写法和EF Core极度类似,因为现在大部分程序员都懒得去写SQL,再一个就是项目作大了或其它原因要改数据库,每次改数据库,那么写的SQL语句大部分要作调整,相当麻烦,并且写SQ ...

  3. Mysql InnoDB Redo log

    一丶什么是redo innodb是以也为单位来管理存储空间的,增删改查的本质都是在访问页面,在innodb真正访问页面之前,需要将其加载到内存中的buffer pool中之后才可以访问,但是在聊事务的 ...

  4. 检测轮廓 获取其最值的坐标 opencv-python

    一.基础知识 图像清晰度评价算法有多种 空域中,主要考察图像的邻域对比度,即相邻像素间灰度特征的 梯度差: 频域中,主要考察图像的频率分量,清晰的图像高频分量多,模糊的图像低频分量多. 灰度值 把白色 ...

  5. kotlin的suspend对比csharp的async&await

    协程的出现大大降低了异步编程的复杂度,可以让我们像写同步代码一样去写异步代码,如果没有它,那么很多异步的代码都是需要靠回调函数来一层层嵌套,这个在我之前的一篇有介绍 rxjava回调地狱-kotlin ...

  6. C++一个吃豆人小游戏

    C++一个吃豆人小游戏 代码如下 #include <cstdio>#include <iostream>#include <ctime>#include < ...

  7. Java开发学习(四十三)----MyBatisPlus查询语句之查询投影

    1.查询指定字段 目前我们在查询数据的时候,什么都没有做默认就是查询表中所有字段的内容,我们所说的查询投影即不查询所有字段,只查询出指定内容的数据. 具体如何来实现? @SpringBootTest ...

  8. LINQ to Entities 不识别方法“System.String get_Item(System.String)”,因此该方法无法转换为存储表达式。

    在使用EF的FirstOrDefault时出现异常.原因是EF的查询条件需要是一个变量否者就会出现这个原因 错误的代码 var userid= db.UserList.Where(u => u. ...

  9. <一>继承的基本意义

    1:继承的本质和原理 2:派生类的构造过程 3:重载,覆盖,隐藏 4:静态绑定和动态绑定 5:多态,vfptr,vftable 6:抽象类的设计原理 7:多重继承以及问题 8:虚基类 vbptr 和v ...

  10. Linux deb系统 nginx 配置解析php

    如果你是root用户可以不加sudo 首先安装php php-fpm nginx sudo apt-get install php php-fpm nginx -y nginx 是一个轻量级的http ...