目录
一、原因分析
二、解决方法
1.直接将线程对象的指针置空
2.借用Object对象保存线程的地址
总结
一、原因分析
由于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对象而报错的原因,并提供了两种简单的方法来避免这一问题,第一个方法具有较大的局限性,除非线程会自动结束且不会对程序后续运行造成重大影响,否则不推荐使用。第二个方法在第一个方法的基础上进行了简单改进,使其可以继续拥有对线程的控制权。
不过这两个方法都只是本人在练习时遇到问题简单做的处理方法,仅代表本人想法,不是解决这类问题的根本方法。