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

次の 2 つのポイントがあります。

First:Threadは NOTであるため、 JavaDocSerializableからの次の抜粋が適用されます。serializable

シリアル化できないクラスのサブタイプをシリアル化できるようにするために、サブタイプは、スーパータイプの public フィールド、protected フィールド、および (アクセス可能な場合) package フィールドの状態を保存および復元する責任を負う場合があります。

つまり、クラスThreadSerializationには の状態を保存および復元する責任がありThreadます。privateしかし、 には多くのフィールドがあるため、それを行うことはできませんThread。したがって、すべてのプライベート フィールドThreadはデフォルトで初期化されます。の実装を見てみましょうThread.start():

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

適切に保存/復元されていないためthreadStatus、もう一度開始できます。

2 つ目: 実際のオペレーティング システム スレッドと "manager" オブジェクトを混同しないでくださいjava.lang.Thread。これらは疎結合です。あなたの例では、マネージャーのみをシリアライズしますが、Java で表現されていない OS スレッドはシリアライズしません。逆シリアル化の後、 OS スレッドが接続されていない2 番目のマネージャー インスタンスが作成されます。したがって、マネージャーに開始するように指示すると成功します。

于 2012-05-16T16:51:21.907 に答える
8

オブジェクトをデシリアライズ (?) すると、基本的に、元のオブジェクトと同じプロパティを持つそのクラスの新しいインスタンスが作成されます。

同じオブジェクトではありません。

同様に、Thread 自体は Serializable を実装していないため、シリアライゼーションは非シリアライズ可能なスーパークラスから継承されたフィールドを復元しないため、開始性は実質的にすべてのシリアライズ可能なサブクラスの一時的な状態の一部です (中断されている場合と同様)。正当な理由があると仮定すると、おそらく、開始性と中断性を追跡し、その状態の要素を呼び出してinまたは復元するためextends Thread implements Serializableの独自のフィールドを持つ必要があるクラス。Thread.start()Thread.interrupt()readObject()readResolve()

于 2012-05-16T16:13:29.650 に答える
1

オブジェクトをシリアライズ可能にするには、それぞれのクラスが Serializable インターフェイスを明示的に実装する必要があります。ただし、"Thread"、"OutputStream"、"Socket" などの Java によって定義された特定のシステム クラスはシリアライズできません。なんでそうなの?一歩戻って、System1 JVM で実行されているスレッドを System1 メモリーを使用してシリアライズし、System2 でデシリアライズして System2 JVM で実行しようとすることの用途は何ですか。理にかなっていますね!したがって、これらのクラスは直列化できません。

あなたのプログラムに来ます。

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

serializable を実装して Thread を拡張したり、Runnable を実装したりするクラスを持つことは非常に悪いことです。まとめ 封印やストリームとソケットの処理ではスレッドを使用しないでください。

于 2013-07-26T07:25:31.733 に答える
1

シリアル化中にオブジェクトのインスタンス変数が吸い出され、バイトに変換されてファイル (通常は拡張子が .ser のファイル) に書き込まれます。次に、逆シリアル化中にファイルからバイトが読み取られ、インスタンス変数に変換されて使用されます。シリアル化されたものと同一の新しいオブジェクトを作成します。それらのコンストラクターは呼び出されないため、作成されたときではなく、シリアル化されたときの状態に到達します。

シリアル化の前にオブジェクトのハッシュコードを確認できますが、逆シリアル化の後は、オブジェクトがヒープ上のどこに作成されるかに応じてハッシュコードが JVM によって提供されるため、同じになることはありません。同じアドレスのヒープ...したがって、それらはdiffオブジェクトですが、状態は同じです。

于 2012-05-16T18:38:52.797 に答える
0

この「スレッド」の他の応答に関係なく:)

ネイティブ メソッドの呼び出しのため、スレッド クラスをシリアル化できません!!!

限目!

編集:

単一のプロセス内で作業している場合は、グローバル変数を宣言できます。複数のスレッドを作成する場合は、アクティブなスレッドのリストを含むクラスを作成できます。

  • このクラスには、ハッシュ マップが含まれます。
  • ハッシュ マップには、キー (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 に答える