Java序列化类在写出到本地时由于存在Thread对象而报错的原因分析的解决方法


一、原因分析

由于Java源码中并没有给Thread类实现Serializable接口,导致如果需要保存的对象中包含线程对象则会报NotSerializableException,具体错误信息如下:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.io.NotSerializableException: java.lang.Thread
……
Caused by: java.io.NotSerializableException: java.lang.Thread

由于线程本身的特性,保存一个线程本身并没有大太的意义,Java可能因此选择了直接拒绝让其可序列化,也就导致了在序列化保存包含线程的对象时必然会报错。


二、解决方法

由于线程本身是不可序列化的,以此这里讨论的是绕开序列化线程后对对象进行序列化的操作

1.直接将线程对象的指针置空

如果不考虑之后要再次使用线程内部数据的话,可以直接将线程对象的指针置空(如果是其他的线程实现方式也要这样做,如实现Runnable接口的对象也要置空),从而让Java认为要保存的内容中没有线程对象。

代码如下:

import java.io.*;

public class Test {
    public static void main(String[] args) throws IOException {
        //创建要保存的对象
        TestClass1 test = new TestClass1();
        //将线程对象和实现Runnable接口的对象置空
        test.myThread=null;
        test.testThread=null;
        //写出文件
        File save = new File("C:\\Users\\15344\\Desktop\\新建文件夹2\\1.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(save));
        objectOutputStream.writeObject(test);
        objectOutputStream.close();
    }
}

class TestClass1 implements Serializable {
    private static final long serialVersionUID = 4322270540833784694L;
    protected MyThread myThread;
    protected Thread testThread;
    public TestClass1() {
        myThread = new MyThread();
        //创建自定义实现Runnable接口的对象
        MyThread myThread = new MyThread();
        //创建线程
        testThread = new Thread(myThread);
        //开启线程
        testThread.start();
    }
}

/**
 * 实现Runnable接口的对象
 */
class MyThread implements Runnable {

    @Override
    public void run() {
        while (true) {
        }
    }
}

注意:虽然线程地址记录为空,但这个线程并没有结束,而是会一直运行下去直到线程本身的任务完成,因此该方法会使线程脱离控制,在使用前要注意线程本身的限制,如对程序后续运行是否有影响,避免出现意外(如上述代码会导致CPU一直高占用,即使IDE与程序断开连接也没用)。

2.借用Object对象保存线程的地址

为避免上述方法中线程脱离控制的情况,我们可以利用Java多态的特性,用Object对象接收Thread对象,并在写出文件之后进行强转将线程还原,这样不仅绕开线程保存了对象,也保证了线程的运行,还避免了线程脱离控制,可谓一石三鸟。

main方法代码如下:

public class Test {
    public static void main(String[] args) throws IOException {
        //创建要保存的对象
        TestClass1 test = new TestClass1();
        //创建Object对象接收
        Object o1 = test.myThread;
        Object o2 = test.testThread;
        //将线程对象和实现Runnable接口的对象置空
        test.myThread = null;
        test.testThread = null;
        //写出文件
        File save = new File("C:\\Users\\15344\\Desktop\\新建文件夹2\\1.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(save));
        objectOutputStream.writeObject(test);
        objectOutputStream.close();
        //还原
        test.myThread = (MyThread) o1;
        test.testThread = (Thread) o2;
    }
}

 这样做了之后就可以继续用原来的方法控制线程


总结

本文简单分析了Java序列化类在写出到本地时由于存在Thread对象而报错的原因,并提供了两种简单的方法来避免这一问题,第一个方法具有较大的局限性,除非线程会自动结束且不会对程序后续运行造成重大影响,否则不推荐使用。第二个方法在第一个方法的基础上进行了简单改进,使其可以继续拥有对线程的控制权。

不过这两个方法都只是本人在练习时遇到问题简单做的处理方法,仅代表本人想法,不是解决这类问题的根本方法。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值