7

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();
        }

    }

}

输出-

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

为什么 ser1 对象又开始了?

4

5 回答 5

16

有两点:

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

为了允许序列化不可序列化类的子类型,子类型可以负责保存和恢复超类型的公共、受保护和(如果可访问)包字段的状态。

这意味着,您的班级ThreadSerialization将有责任存储和恢复Thread. 但是你不能这样做,private因为Thread. 因此,所有私有字段Thread都默认初始化。现在看看实现Thread.start()

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

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

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

于 2012-05-16T16:51:21.907 回答
8

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

它不是同一个对象。

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

于 2012-05-16T16:13:29.650 回答
1

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

您可以在序列化之前检查对象的哈希码,然后在反序列化之后,它们将永远不会相同,因为哈希码由 JVM 提供,具体取决于在堆上创建对象的位置,很明显这两个对象不能在堆在同一个地址......所以它们是不同的对象,但具有相同的状态。

于 2012-05-16T18:38:52.797 回答
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 的类是非常糟糕的。总结 不要在密封或流和套接字过程中使用线程。

于 2013-07-26T07:25:31.733 回答
0

无论此“线程”中的任何其他响应如何:)

由于调用了 Native Methods,Thread 类不能被序列化!!!

时期!

编辑:

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

  • 此类包含哈希映射。
  • 哈希映射包含作为字符串的键(id)和作为对线程的弱引用的值。
  • 线程由 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();
    }

}
于 2015-07-01T20:14:28.993 回答