1

stop()サーバーを閉じるメソッドを持つクライアントを受け入れるサーバーがあり、java.nio.AsynchronousCloseException解決したい問題が発生しています。メソッドは別のstop()スレッドで呼び出されます。これが競合状態の原因だと思います。

これが私のコードです:

public void run() {
    InetSocketAddress addr = new InetSocketAddress(provider.getConnection(), 12354);
    try {
        server = ServerSocketChannel.open();
        server.configureBlocking(true);
        server.socket().bind(addr);
        parent.setIP(addr.getAddress().getHostAddress().toString());
        password = generatePassword();
        parent.setPassword(password);
        parent.setStatus("Ready.");
    } catch (IOException e) {
        parent.die("Could not start server: " + e.getMessage());
        runner = null;
    }
    while (runner == Thread.currentThread()) {
        try {
            SocketChannel sc = server.accept();
            if (available) {
                session = new ReceiveSession(this, sc, password, addr.getAddress());
                session.start();
                available = false;
            } else {
                new ReceiveBusyHandler(sc).start();
            }
        } catch (IOException e) {
            synchronized (swallowException) {
                if (!swallowException) {
                    parent.showError(e.toString());
                }
                available = true;
            }
        }
    }
}

public void stop() throws IOException {
    synchronized (swallowException) {
        swallowException = true;
        runner = null;
        if (server != null) {
            server.socket().close();
            server.close();
        }

        swallowException = false;
        System.out.println("Server down");
    }
}

(参考までに、同期を試みswallowExceptionBooleanことがわかります。)

サーバーループの例外ハンドラーがアクセスする前に、stop()メソッドが設定swallowExceptionされtrueてから元に戻っているようです。false

更新:Objectロックとして使用する新しいものを導入しwait()/notify()、問題を修正するために使用しました:

public void run() {
        InetSocketAddress addr = new InetSocketAddress(provider.getConnection(), 12354);
        try {
            server = ServerSocketChannel.open();
            server.configureBlocking(true);
            server.socket().bind(addr);
            parent.setIP(addr.getAddress().getHostAddress().toString());
            password = generatePassword();
            parent.setPassword(password);
            parent.setStatus("Ready.");
        } catch (IOException e) {
            parent.die("Could not start server: " + e.getMessage());
            runner = null;
        }
        while (runner == Thread.currentThread()) {
            try {
                SocketChannel sc = server.accept();
                if (available) {
                    session = new ReceiveSession(this, sc, password, addr.getAddress());
                    session.start();
                    available = false;
                } else {
                    new ReceiveBusyHandler(sc).start();
                }
            } catch (IOException e) {
                synchronized (lock) {
                    if (!swallowException) {
                        parent.showError(e.toString());

                    }
                    lock.notify();
                    available = true;
                }
            }
        }
    }

    public void stop() throws IOException {
        synchronized (lock) {
            swallowException = true;
            runner = null;
            if (server != null) {
                server.socket().close();
                server.close();
            }
            while (swallowException) {
                try {
                    lock.wait();
                    swallowException = false;
                } catch (InterruptedException e) {
                }
            }
            //swallowException = false;
            System.out.println("Server down");
        }
    }
4

3 に答える 3

1

この部分は正しく同期されていません:

synchronized (swallowException) {
    swallowException = true;

1 つのインスタンス ( false) で同期し、すぐに別のインスタンス ( ) を指すようにswallowException 参照trueを変更しています。次に入るスレッドstopはブロックされません。

スワップ アウトされないインスタンス (これらのメソッドの所有者) で同期するか、.NET の他のロック メカニズムを使用しjava.util.concurrentます。

于 2013-04-28T10:39:34.593 に答える
1

Java では、変数ではなくオブジェクトに対して同期が行われます。で同期するとswallowException、その値 (Boolean.TRUEまたはBoolean.FALSE) で同期されます。これはあなたが望むものではありません。を含むオブジェクトで同期する必要がありますswallowException

于 2013-04-28T10:40:02.940 に答える
0

何が起こっているのかはっきりしないため、コードをリファクタリングすることを強くお勧めします (更新として投稿したソリューションであっても)。

あなたの説明から、スレッドセーフな方法でサーバーを停止したいだけのようです。これを行うことをお勧めします。これにより、 ServerSocketで close() を呼び出すだけで、 a をキャッチできるようになりますSocketException

private boolean cont = true;

// this can safely be called from any thread
public synchronized void stop() {
    cont = false;
    if (server != null) {
       server.socket().close();
    }
}
private synchronized void setContinue(boolean value) {
    cont = value;
}
private synchronized boolean shouldContinue() {
    return cont;
}
private synchronized void openChannel() {
    server = ServerSocketChannel.open();
}

public void run() {
    InetSocketAddress addr = new InetSocketAddress(provider.getConnection(), 12354);
    try {
        openChannel();
        server.configureBlocking(true);
        server.socket().bind(addr);
        parent.setIP(addr.getAddress().getHostAddress().toString());
        password = generatePassword();
        parent.setPassword(password);
        parent.setStatus("Ready.");
    } catch (IOException e) {
        parent.die("Could not start server: " + e.getMessage());
        setContinue(false);
    }

    while (shouldContinue()) {
        try {
            SocketChannel sc = server.accept();
            if (shouldContinue()) {
                if (available) {
                    session = new ReceiveSession(this, sc, password, addr.getAddress());
                    session.start();
                    available = false;
                } else {
                    new ReceiveBusyHandler(sc).start();
                }
            }
        } catch (SocketException se) {
            // normal shutdown from stop()
        } catch (IOException e) {
            parent.showError(e.toString()); 
            available = true;               
        }
    }
    System.out.println("Server down");
}

サーバーを停止するためのこの手法の詳細については、こちらを参照してください

于 2013-04-28T10:56:50.413 に答える