Java构建SerializedCache对象,实现对数据的序列化和反序列化

问题提出:缓存对象取出数据时出现的线程不安全问题?

        昨天写了FIFO和LRU以及日志的缓存对象,这些缓存对象都是用来缓存数据的,但是会出现一个问题。我们提供了缓存数据的对象后,用户在缓存数据后,想要将数据取出时,并不是真的将数据对象取出,而是取出一个对象的引用。真正的数据对象还是存在在内存中的,我们只是引用了它,这个时候就出现问题了,当多个用户同时操作这个数据对象时,就会出现线程不安全的状态。
        为什么会出现这种状态?
        其实就是因为,多个用户同时共享一个数据对象时,同时都引用这一个数据对象。如果有用户修改了这个数据对象,那么其他用户拿到的就是已经修改过的对象,这样就是出现了线程不安全。
        如何处理这个问题?

解决办法

        两种方法:第一种方法就是加锁,但是这样就会导致,一个用户在操作对象时,其他用户只能等着,这样设计,会影响性能。第二种方法就是通过对象的序列化和反序列化来实现。
        我们知道,对象在实现了序列化接口之后就可以被序列化成字节来存储,而在反序列化的时候,是将字节在反序列化成原来的数据。注意这里是数据,只是数据一样而已,对象已经不是原来的对象了。因为字节在被反序列化时,会在创建一个新的对象,这个新的对象的数据和原来对象的数据一模一样。
        所以这样有了序列化和反序列化的设计,就解决了线程不安全的问题。用户在添加或者取出数据时,我们让数据对象经过SerializedCache的序列化和反序列化处理之后。取出时都会取出一个新的对象。

上代码

        问题已经分析完了,接下来直接上代码。

package com.test.prictice;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializedCache implements Cache{
	
	private Cache cache;
	
	public SerializedCache(Cache cache) {
		this.cache=cache;
	}

	@Override
	public void putObject(Object key, Object value) {
		cache.putObject(key, serialize((Serializable) value));
	}
	@Override
	public Object getObject(Object key) {
		Object value = cache.getObject(key);
		Serializable result  = deserialize((byte[]) value);
		return result;
	}

	@Override
	public Object removeObject(Object key) {
		return null;
	}
	

	/**
	 * 对象序列化方法
	 * @param value
	 * @return
	 */
	private Object serialize(Serializable value) {
		//序列化方法利用ObjectOutputStream
		//声明字节数组输出流
		ByteArrayOutputStream bos = null;
		//声明对象输出流
		ObjectOutputStream oos=null;
		try {
			//1.构建ObjectOutStream对象和字节数组对象
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			//2.将对象序列化到数组
			oos.writeObject(value);
			//刷新对象输出流
			oos.flush();
			//关闭对象输出流
			oos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bos.toByteArray();
	}
	

	/**
	 * 对象反序列化方法
	 * @param value
	 * @return
	 */
	private Serializable deserialize(byte[] value) {
		//声明对象输入流
		ObjectInputStream ois=null;
		//声明字节数组输入流
		ByteArrayInputStream bis = null;
		Serializable result=null;
		try {
			//构建字节数组输入流
			bis = new ByteArrayInputStream(value);
			//构建对象数组输入流
			ois=new ObjectInputStream(bis);
			result = (Serializable) ois.readObject();
			ois.close();
		} catch (IOException | ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

}

注意:序列化的时候,数据对象一定要实现序列化接口。
这是我的公众号YuFeng7604,欢迎交流!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值