0

在庫のArrayListをファイルに永続化する分散システムを設計しています。ファイルにストックを書き込んでいますが、そのファイルを読み取ると、nullポインター例外エラーが発生します。

これはクラスAのフィールドです。

private static StockList instance = null;

これは、クラスAのgetInstance()メソッドで、ファイルから株式のリストを取得します。

public static StockList getInstance(){
    if (instance==null){
        try {
            XMLDecoder d = new XMLDecoder(
                    new BufferedInputStream(
                    new FileInputStream("Stock.xml")));
            instance = (StockList) d.readObject();
            d.close();
        } catch (IOException ex) {
            instance= new StockList();
            Logger.getLogger(StockList.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }
    return instance;
}

これはクラスAコンストラクターであり、getInstance()にIOExceptionがある場合に呼び出されます。

public StockList(){
    stock.put("APL", new Stock("APL","Apple","Apple",3200));
    System.out.println("");
}

これは、クラスAのwriteStockListメソッドで、ストックをファイルに書き込みます。

public void writeStockList()
    {
       try {
            XMLEncoder e = new XMLEncoder(
                new BufferedOutputStream(
                new FileOutputStream("Stock.xml")));
        e.writeObject(getInstance());
        e.flush();
        e.close();            
    } catch (IOException ex) {            
        Logger.getLogger(StockList.class.getName()).log(Level.SEVERE, null, ex);
    }
}

これは、サーバーの実行時にストックリストを初期化するクラスBの私のメインメソッドです。

public static void main(String[] args){
    try {
        //Make sure all lists are initialised
        StockList.getInstance();
        //delete after first run
        //StockList.getInstance().addStock(new Stock("APL2","Apple2","Apple",3200));
        //StockList.getInstance().writeStockList();
        System.out.println(StockList.getInstance().getStock("APL" ).name);          
        System.out.println(StockList.getInstance().getStock("APL2" ).name);

        System.out.println("registered ok");
    } catch (RemoteException ex) {
        Logger.getLogger(ClientServer.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("finished server setup");
}

テストの目的で、プログラムを初めて実行するときは、次の行のコメントが解除されます。

//StockList.getInstance().addStock(new Stock("APL2","Apple2","Apple",3200));  
//StockList.getInstance().writeStockList();

これにより、新しい在庫(APL2)がリストに追加され、ファイルに書き込まれます。

次の行は正しく印刷されています-両方の株が見つかったことを証明しています:

System.out.println(StockList.getInstance().getStock("APL" ).name);          
System.out.println(StockList.getInstance().getStock("APL2" ).name);

次に、2回目の実行時に、上記の行がコメント化されますが、上記のSystem.out.printlnは次のエラーをスローします。

Exception in thread "main" java.lang.NullPointerException at food.stockticker.priceserver.ClientServer.main(ClientServer.java:46)
Java Result: 1

getInstance()が呼び出されたときに、2番目の項目がファイルに書き込まれ、ストックリストに読み戻されるため、上記は発生しないはずです。最初のアイテム(APL)を印刷すると、それが返されます。APL2を印刷すると、エラーが発生します。

Stock.xmlファイルが上書きされたか、最初の実行で行われた変更がxmlファイルに書き込まれなかったかのようです。何か案は?

編集:

XML:

<?xml version="1.0" encoding="UTF-8"?> 
<java version="1.6.0_41" class="java.beans.XMLDecoder"> 
<object class="food.stockticker.priceserver.StockList"/> 
</java> 
4

1 に答える 1

1

私が正しく理解していれば、ファイルは最初の実行後に削除され、コメントアウトされた行が戻されました。この場合、ファイルはこの時点では存在せず、リーダーは初期化されず、多くのものがnullになります、インスタンスを含む-したがってNullPointerException

また、これが分散(マルチスレッド並行)システム用に構築されている場合は、次の点にも注意してください。

メインストックオブジェクトのインスタンスが1つだけであると想定される場合は、シングルトンパターンを使用します。この場合、データはファイルから読み取られるため、ローダーの周囲にロックを設定します(別の方法にします)。 )。この場合、静的{}ロード時にこれを実行することをお勧めします。これにより、1回だけ実行されることが保証され、並行性の高いシステムで機能しないロックを再確認する必要がなくなります。

private static synchronized void load()
{
 // return if file is already loaded, unless you meant to re-load
 // load the file here...
}

そうしないと、複数の同時スレッドが同時にgetInstanceを呼び出す可能性があり、ストックオブジェクトは引き続き実行/ヌルになり、相互にウォークオーバーします。設計とコードには、この質問を超える多くの問題もありますが、これでNPEの問題が解決されることを願っています。

于 2013-03-07T18:48:18.320 に答える