Java线程序列化,为什么序列化的线程对象可以启动

时间:2012-05-16 16:09:25

标签: java serialization

java中的一个线程无法在Java中重启,所以我实现了一个java Thread,然后在获取Thread的序列化对象后尝试重启该线程。

import java.io.Serializable;

public class ThreadSerialization extends Thread implements Serializable {

    int iCheck = 10;
    @Override
    public void run() {
        System.out.println("STARTING");
        for(int i=0;i<10;i++){
            iCheck+=i;
        }
    }

}

和序列化算法 -

public class CallingThreadSerializable {

    public static void main(String[] args) {
        ThreadSerialization ser = new ThreadSerialization();
        ser.start();
        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try {
            fos = new FileOutputStream("thread.ser");
            out = new ObjectOutputStream(fos);
            out.writeObject(ser);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        try {
            fis = new FileInputStream("thread.ser");
            ois = new ObjectInputStream(fis);
            ThreadSerialization ser1 = (ThreadSerialization) ois.readObject();
            System.out.println("---> " + ser1.iCheck);
            ser1.start();
            System.out.println("---> " + ser1.iCheck);
            ois.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

OUTPUT -

STARTING
---> 55
---> 55
STARTING

为什么ser1对象重新开始?

5 个答案:

答案 0 :(得分:16)

有两点:

首先:Thread不是Serializable,因此适用于serializable JavaDoc的以下摘录:

  

要允许序列化非序列化类的子类型,     子类型可能承担保存和恢复的责任     超类型的公共状态,受保护状态和(如果可访问)     包字段。

这意味着,您的班级ThreadSerialization将有责任存储和恢复Thread的状态。但由于private中的许多Thread字段,您无法做到这一点。因此,Thread中的所有私有字段都是默认初始化的。现在看看Thread.start()

的实现
    //...
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    // ...
    start0();
    //...

由于threadStatus尚未正确存储/恢复,您可以再次开始。

第二:不要混淆实际的操作系统线程和“管理器”对象java.lang.Thread - 它们只是松散耦合。在您的示例中,您只序列化管理器,但不序列化在Java中没有表示的OS线程。反序列化后,您有第二个管理器实例 no 附加OS线程。所以告诉经理开始会成功。

答案 1 :(得分:8)

如果你反序列化(?)一个Object,那么你实际上是在创建一个具有与原始Object相同属性的新类实例。

它不是同一个对象。

同样,由于Thread本身没有实现Serializable,因此启动性实际上是任何Serializable子类中的瞬态状态的一部分(因为中断),因为序列化不会恢复从非Serializable超类继承的字段。 extends Thread implements Serializable假定有充分理由这样做的任何一个类都应该有自己的字段来跟踪开始和中断,并在{{1}中调用Thread.start()Thread.interrupt() }或readObject()恢复其状态的元素。

答案 2 :(得分:1)

在序列化期间,对象实例变量被抽出,并转换为字节并写入文件(通常是扩展名为.ser的文件),然后,在反序列化过程中,从文件中读取字节,然后转换为实例变量,并用于创建与序列化的对象相同的新对象。它们的构造函数从不被调用,因此它在序列化时达到状态,而不是在它被创建时。

您可以在序列化之前检查对象的哈希码,然后在反序列化之后,它们永远不会相同,因为JVM提供的哈希码取决于在堆上创建对象的位置,并且显而易见的是2个对象不能在堆上创建的同一地址...所以它们是diff对象但状态相同。

答案 3 :(得分:1)

要使对象可序列化,相应的类应显式实现Serializable接口。但是,由Java定义的某些系统类(如“Thread”,“OutputStream”,“Socket”)不可序列化。为什么这样?让我们退后一步 - 现在使用System1内存序列化在System1 JVM中运行的线程然后在System2中反序列化并尝试在System2 JVM中运行是什么用途。有道理!因此,这些类不可序列化。

来参加你的节目。

ThreadSerialization ser1 = (ThreadSerialization) ois.readObject();// Thread started in System2.
ser1.start();// Thread once again started here in System2.

有一个实现可序列化的类并扩展Thread或实现Runnable是非常糟糕的。 综上所述 不要在密封或流和插座过程中使用螺纹。

答案 4 :(得分:0)

无论此“线程”中的任何其他回复:)

由于调用Native Methods !!!

,无法序列化线程类

期!

编辑:

如果您在单个流程中工作,则可以声明全局变量。 如果您创建多个线程,则可以创建一个包含活动线程列表的类。

  • 此类包含哈希映射。
  • 哈希映射包含一个键(id)作为String,值包含作为对线程的弱引用。
  • 线程由id
  • 标识
  • 您不必担心GC如果您的线程完成或完成它自己的类方法返回null。
import java.lang.ref.WeakReference;
import java.util.HashMap;

public class ThreadsMap {

    private HashMap<String, WeakReference<Thread>> _threadHashMap;

    public ThreadsMap() {
        _threadHashMap = new HashMap<>();
    }

    public void add(String id, Thread thread) {
        WeakReference<Thread> threadWeakReference = new WeakReference<>(thread);
        _threadHashMap.put(id, threadWeakReference);
    }

    public Thread get(String id) {
        WeakReference<Thread> threadWeakReference = _threadHashMap.get(id);
        return threadWeakReference.get();
    }

}