首页 > 其他分享 >【序列化和反序列化】Kryo

【序列化和反序列化】Kryo

时间:2022-12-09 16:22:36浏览次数:56  
标签:kryo 对象 Kryo 线程 new 序列化

  

一、Kryo介绍

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

Kryo序列化出的结果,是其自定义的,独有的一种格式。由于其序列化出的结果是二进制的,也即byte[],因此像redis这样可以存储二进制数据的存储引擎是可以直接将Kryo序列化出来的数据存进去。当然你也可以选择转换成String的形式存储在其他存储引擎中(性能有损耗)。

github地址:https://github.com/EsotericSoftware/kryo

 

二、基础用法

引入依赖

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

基本使用如下所示

package com.chenly.serialize.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 *
 * @author: chenly
 * @date: 2022-11-28 15:07
 * @description:
 * @version: 1.0
 */
public class KryoTest {

    static public void main(String[] args)  {
        SomeClass object = new SomeClass();
        object.value = "Hello Kryo!";

        Kryo kryo = new Kryo();
        kryo.register(SomeClass.class);
        //序列化
        Output output = new Output(new ByteArrayOutputStream());
        kryo.writeObject(output, object);
        byte[] bytes = output.getBuffer();
        output.close();
        //反序列化
        Input input = new Input(new ByteArrayInputStream(bytes));
        SomeClass object2 = kryo.readObject(input, SomeClass.class);
        input.close();
        System.out.println(object2.value);
    }

    static public class SomeClass {
        String value;
    }

}

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

 

三、Kryo的注册

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

kryo.register(SomeClass.class);

或者

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

 

四、Kyro对象引用

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

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

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

 

五、Kyro线程不安全

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

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

 

ThreadLocal + Kryo解决线程不安全

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

private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>(){
    @Override
    protected Kryo initialValue() {
        Kryo kryo = new Kryo();
        return kryo;
    };
};

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

Kryo kryo = kryoThreadLocal.get();

 

ThreadLocal + Kryo解决线程不安全

「池」是一种非常重要的编程思想,连接池、线程池、对象池等都是「复用」思想的体现,通过将创建的“对象”保存在某一个“容器”中,以便后续反复使用,避免创建、销毁的产生的性能损耗,以此达到提升整体性能的作用。

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

Pool<Kryo> kryoPool = new Pool<Kryo>(true,false,8) {
    @Override
    protected Kryo create() {
        Kryo kryo = new Kryo();
     ... //kryo配置
        return kryo;
    }
};

创建Kryo池时需要传入三个参数,其中第一个参数用于指定是否在pool内部使用同步,如果指定为true,则允许被多个线程并发访问。第三个参数是用于指定对象池的大小的。

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

 

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

//获取池中的Kryo对象
Kryo kryo =  kryoPool.obtain();
//将Kryo对象归还到池中
kryoPool.free(kryo);

 理论上,只要对象池大小评估得当,就能在占用极小内存空间的情况下完美解决并发安全问题

 

六、小结

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

 

标签:kryo,对象,Kryo,线程,new,序列化
From: https://www.cnblogs.com/kiko2014551511/p/16932859.html

相关文章

  • 集合对象序列化
    packagecom.itheima.d5_serializable;importjava.io.Serializable;###//类的对象如果要序列化,必须实现Serializable接口。publicclassUserimplementsSerializ......
  • CVE-2015-4852 Weblogic T3 反序列化分析
    0x01前言看到很多师傅的面经里面都有提到Weblogic这一个漏洞,最近正好有一些闲暇时间,可以看一看。因为环境上总是有一些小问题,所以会在本地和云服务器切换着调试。0x0......
  • java安全 反序列化(一)
    介绍序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。序列化是一种对象持久化的手段,可以将对象的状态转换为字节数组,来......
  • jquery form表单.serialize()序列化后中文乱码问题原因及解决
    有时候我们需要使用ajax提交去提交form的值,这样就需要使用serialize()去获取form的值,但这样获取的值如果有中文,会乱码,原因和解决方法如下:原因:.serialize()自动调用了encodeU......
  • 7 I/O和序列化
    HeadFirstJava和AcWingJava课程做的总结7。7.1输入&输出输入方式1,效率较低,输入规模较小时使用。(10e6分界条件)importjava.util.Scanner;publicclassMain{......
  • 【序列化和反序列化】Protostuff
    一、protostuff介绍protostuff基于Googleprotobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime实现了无需预编译对javabean进行protobuf序列化/反序......
  • Form表单序列化Json插件-jquery.serializejson.min.js
    Form表单参数序列化成Json对象:​​1.使用serializeJsonObject​​​​2.jquery.serializejson.min.js​​1.使用serializeJsonObject在低版本的jQ中,可以使用serializeJso......
  • 【序列化】Java中将使用PHP序列化工具将数据序列化
    在项目中需要和PHP公用一个MySQL数据库,有些数据需要序列化之后保存,这就需要将待存储的数据序列化之后存到数据库中,取出的时候,需要反序列化之后才能正常使用。原数据:{"06008......
  • 使用.NET7和C#11打造最快的序列化程序-以MemoryPack为例
    使用.NET7和C#11打造最快的序列化程序-以MemoryPack为例 译者注本文是一篇不可多得的好文,MemoryPack的作者neuecc大佬通过本文解释了他是如何将序列化程序性能提......
  • Newtonsoft.Json 对象序列化 -- 系列文章
    Newtonsoft.Json是一个非常棒的.net对象转Json,Json字符串转对象的类库,此分类中主要记录日常使用的方法以及功能总结。三:C#对象转换Json时的一些高级(特殊)设置;二:C#对......