「周末福报」如何高效使用 Kryo

时间:2022-07-24
本文章向大家介绍「周末福报」如何高效使用 Kryo,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Kryo 本身是多线程不安全的。

捣鼓、尝试了两种处理方式:ThreadLocal、KryoPool。


ThreadLocal

public class KryoUtil {

  final static ThreadLocal<Kryo> kryoLocal = new ThreadLocal<Kryo>() {
    @Override
    protected Kryo initialValue() {
      Kryo kryo = new Kryo();
      kryo.setClassLoader(Thread.currentThread().getContextClassLoader());
      // 提前注册好需要处理的序列化对象
      kryo.register(String.class);
      kryo.register(UserDTO.class, new BeanSerializer<>(kryo, UserDTO.class));
      return kryo;
    }
  };

  public static byte[] serialize(Object object) {
    Output output = new Output(new ByteArrayOutputStream());
    try {
      kryoLocal.get().writeObject(output, object);
      return output.getBuffer();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    } finally {
      output.close();
      output.flush();
    }
  }

  @SuppressWarnings("unchecked")
  public static <T> T deserialize(byte[] bytes, Class<?> type) {
    Input input = new Input(new ByteBufferInput(bytes));
    try {
      Kryo kryo = kryoLocal.get();
      return (T) kryo.readObject(input, type);
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    } finally {
      input.close();
    }
  }
}

KryoPool

public class KryoPoolUtil {
  private static Pool<Kryo> kryoPool = new Pool<Kryo>(true, false, 8) {
    protected Kryo create() {
      Kryo kryo = new Kryo();
      kryo.setRegistrationRequired(false);
      kryo.setReferences(false);
      return kryo;
    }
  };

  public static byte[] serialize(Object object) {
    Kryo kryo = kryoPool.obtain();
    Output output = new Output(new ByteArrayOutputStream());
    try {
      kryo.writeObject(output, object);
      return output.getBuffer();
    } finally {
      kryoPool.free(kryo);
      output.close();
      output.flush();
    }
  }

  @SuppressWarnings("unchecked")
  public static <T> T deserialize(byte[] bytes, Class<?> type) {
    Kryo kryo = kryoPool.obtain();
    Input input = new Input(new ByteBufferInput(bytes));
    try {
      return (T) kryo.readObject(input, type);
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    } finally {
      kryoPool.free(kryo);
      input.close();
    }
  }
}

遇到的坑

连续处理两个对象序列化/反序列化遇到的未注册错误

解决方式:将需要处理的对象类,提前注册到 Kryo。

 // 注册需要处理的类
kryo.register(String.class);
kryo.register(UserDTO.class, new BeanSerializer<>(kryo, UserDTO.class));

小结

线程不安全的类,大都可以采用以上两种方法来进行。

这个周末,又一次成功“强迫”自己学习。

感谢各位小伙伴的阅读,这里是一个技术人的学习与分享。