当前位置: 首页 > 工具软件 > Kryo > 使用案例 >

Kryo高效率序列反序列化

皇甫喜
2023-12-01

前言

基于Java的快速高效的对象序列化框架,旨在提供快速、高效和易用的API。无论文件、数据库或网络数据Kryo都可以随时完成序列化。Kryo还可以执行自动深拷贝(克隆)、浅拷贝(克隆),这是对象到对象的直接拷贝,非对象→字节→对象的拷贝。支持互相引用,比如类A引用类B,类B引用类A,可以正确地反序列化。

如何使用

导入依赖

创建一个普通的maven工程,导入kyro依赖

        <!-- kryo序列化-->
        <dependency>
            <groupId>com.esotericsoftware</groupId>
            <artifactId>kryo-shaded</artifactId>
            <version>4.0.2</version>
        </dependency>

配置kyro

多线程场景下的配置

package com.jcl.config;

/**
 * 序列化工具(程序调用该接口来实现obj<->byte[]之间的序列化/反序列化)
 */
public interface Serializer{

    /**
     * 序列化
     */
    public void serialize(Object t,byte[] bytes);

    /**
     * 序列化
     */
    public void serialize(Object obj, byte[] bytes, int offset, int count);

    /**
     * 反序列化
     */
    public <T>T deserialize(byte[] bytes);

    /**
     * 反序列化
     */
    public <T>T deserialize(byte[] bytes, int offset, int count);
}

实现类:

package com.jcl.config;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.BeanSerializer;

/**
 * 基于kyro的序列化/反序列化工具
 */
public class kryoSerializer implements Serializer
{

    // 由于kryo不是线程安全的,所以每个线程都使用独立的kryo
    final ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>()
    {
        @Override
        protected Kryo initialValue()
        {
            Kryo kryo = new Kryo();
            kryo.register(ct, new BeanSerializer<>(kryo, ct));
            return kryo;
        }
    };

    // 序列化threadlocal
    final ThreadLocal<Output> outputLocal = new ThreadLocal<Output>();

    // 反序列化threadlocal
    final ThreadLocal<Input> inputLocal = new ThreadLocal<Input>();

    private Class<?> ct = null;

    public kryoSerializer(Class<?> ct)
    {
        this.ct = ct;
    }

    /**
     * 序列化
     */
    @Override
    public void serialize(Object obj, byte[] bytes)
    {
        Kryo kryo = getKryo();
        Output output = getOutput(bytes);
        kryo.writeObjectOrNull(output, obj, obj.getClass());
        output.flush();
    }

    /**
     * 序列化
     */
    @Override
    public void serialize(Object obj, byte[] bytes, int offset, int count)
    {
        Kryo kryo = getKryo();
        Output output = getOutput(bytes, offset, count);
        kryo.writeObjectOrNull(output, obj, obj.getClass());
        output.flush();
    }

    /**
     * 反序列化
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T deserialize(byte[] bytes, int offset, int count)
    {
        Kryo kryo = getKryo();
        Input input = getInput(bytes, offset, count);
        return (T) kryo.readObjectOrNull(input, ct);
    }

    /**
     * 反序列化
     */
    @Override
    public <T> T deserialize(byte[] bytes)
    {
        return deserialize(bytes, 0, bytes.length);
    }

    /**
     * 获取kryo
     */
    private Kryo getKryo()
    {
        return kryoLocal.get();
    }

    /**
     * 获取Output并设置初始数组
     */
    private Output getOutput(byte[] bytes)
    {
        Output output = null;
        if ((output = outputLocal.get()) == null)
        {
            output = new Output();
            outputLocal.set(output);
        }
        if (bytes != null)
        {
            output.setBuffer(bytes);
        }
        return output;
    }

    /**
     * 获取Output
     */
    private Output getOutput(byte[] bytes, int offset, int count)
    {
        Output output = null;
        if ((output = outputLocal.get()) == null)
        {
            output = new Output();
            outputLocal.set(output);
        }
        if (bytes != null)
        {
            output.writeBytes(bytes, offset, count);
        }
        return output;
    }

    /**
     * 获取Input
     */
    private Input getInput(byte[] bytes, int offset, int count)
    {
        Input input = null;
        if ((input = inputLocal.get()) == null)
        {
            input = new Input();
            inputLocal.set(input);
        }
        if (bytes != null)
        {
            input.setBuffer(bytes, offset, count);
        }
        return input;
    }

    public Class<?> getCt()
    {
        return ct;
    }

    public void setCt(Class<?> ct)
    {
        this.ct = ct;
    }
}

测试

原生序列化

package com.jcl.test;

import com.jcl.sample.Simple;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * jdk自带的序列化性能测试
 * @author 朝花不迟暮
 * @version 1.0
 * @date 2020/10/27 20:55
 */
public class OriginalSerializable
{
    public static void main(String[] args) throws IOException
    {
        long start =  System.currentTimeMillis();
        setSerializableObject();
        System.out.println("java原生序列化时间:" + (System.currentTimeMillis() - start) + " ms" );
        start =  System.currentTimeMillis();
        getSerializableObject();
        System.out.println("java原生反序列化时间:" + (System.currentTimeMillis() - start) + " ms");
    }


    public static void setSerializableObject() throws IOException
    {

        FileOutputStream fo = new FileOutputStream("D:/test.txt");

        ObjectOutputStream so = new ObjectOutputStream(fo);

        for (int i = 0; i < 100000; i++) {
            Map<String,Integer> map = new HashMap<>(2);
            map.put("zhang0", i);
            map.put("zhang1", i);
            so.writeObject(new Simple("zhang"+i,(i+1),map));
        }
        so.flush();
        so.close();
    }

    public static void getSerializableObject(){
        FileInputStream fi;
        try {
            fi = new FileInputStream("D:/test.txt");
            ObjectInputStream si = new ObjectInputStream(fi);

            Simple simple =null;
            while((simple=(Simple)si.readObject()) != null){
                //System.out.println(simple.getAge() + "  " + simple.getName());
            }
            fi.close();
            si.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            //e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

kyro序列化

package com.jcl.test;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.jcl.sample.Simple;
import org.objenesis.strategy.StdInstantiatorStrategy;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * https://mp.weixin.qq.com/s?__biz=MzU0NDA2MjY5Ng==&mid=2247490672&idx=1&sn=4a1e57f8fc63de2ba611e90e87224766&chksm=fb00b1f7cc7738e18cea6a8d70748a5172f30dbab537121f72ec1d4f90398c905abeebb78dbd&mpshare=1&scene=23&srcid=10271rQmC5mYRMWMuRQnzO2R&sharer_sharetime=1603799292215&sharer_shareid=7da19e92911183dd19f355111ebfa2dc#rd
 * @author 朝花不迟暮
 * @version 1.0
 * @date 2020/10/27 21:01
 */
public class KyroSerializable
{
    public static void main(String[] args) throws IOException
    {
        long start =  System.currentTimeMillis();
        setSerializableObject();
        System.out.println("Kryo 序列化时间:" + (System.currentTimeMillis() - start) + " ms" );
        start =  System.currentTimeMillis();
        getSerializableObject();
        System.out.println("Kryo 反序列化时间:" + (System.currentTimeMillis() - start) + " ms");

    }

    public static void setSerializableObject() throws FileNotFoundException{

        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.setRegistrationRequired(false);
        kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
        kryo.register(Simple.class);
        Output output = new Output(new FileOutputStream("D:/file1.txt"));
        for (int i = 0; i < 100000; i++) {
            Map<String,Integer> map = new HashMap<String, Integer>(2);
            map.put("zhang0", i);
            map.put("zhang1", i);
            kryo.writeObject(output, new Simple("zhang"+i,(i+1),map));
        }
        output.flush();
        output.close();
    }


    public static void getSerializableObject(){
        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.setRegistrationRequired(false);
        kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
        Input input;
        try {
            input = new Input(new FileInputStream("D:/file1.txt"));
            Simple simple =null;
            while((simple=kryo.readObject(input, Simple.class)) != null){
                //System.out.println(simple.getAge() + "  " + simple.getName() + "  " + simple.getMap().toString());
            }

            input.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch(KryoException e){

        }
    }
}

从效率上来看,提升了十倍!如果想详细了解点链接了解详情

 类似资料: