1

作为我研究的一部分,我尝试在 Java RMI 中实现一个客户端-服务器软件来解决哲学家就餐问题(https://en.wikipedia.org/wiki/Dining_philosophers_problem )。

网络必须能够识别意外断开连接(fe 崩溃)的客户端并恢复其状态。目前,我的服务器应用程序跟踪网络中的所有客户端(注册新客户端、重置其他客户端以分发椅子),但不跟踪它们的状态。

因此,我想使用一个主动系统,一旦其中一个客户端无法连接到另一个客户端,它将使用服务器上的 RMI 函数来删除客户端(首先从服务器上的 ArrayList 中删除它,然后删除它完全通过重置所有客户端):


来自 Server.java 的片段

@Override
public synchronized boolean deleteClient(String IP) throws RemoteException, ServerNotActiveException {
    if(clients.contains(IP)) {  
        log.log(Level.FINE, "Remove inactive client {0} from ArrayList...", IP);
        clients.remove(IP);
        return true;
    }
    return false;
}

@Override
public void removeClient(String IP) throws RemoteException, ServerNotActiveException {
    log.log(Level.FINE, "Removing inactive client {0} from the system...", IP);
    resetClientsForRemoval();
}

来自 Client.java 的片段

catch (ConnectException e) {
    log.log(Level.SEVERE, "Client seems to be down\n", e);
    if (server.deleteClient(IP)) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    server.removeClient(IP);
                } catch (RemoteException e) {
                    log.log(Level.SEVERE, "Error during removal.\n", e);
                } catch (ServerNotActiveException e) {
                    log.log(Level.SEVERE, "Error during removal.\n", e);
                }
            }
        }).start();
    }
}

这意味着我首先检查是否可以从 ArrayList 中删除客户端(或者其他人是否已经将其删除),然后通过重置网络中的所有客户端来执行客户端的最终删除。

但现在我有一个问题。Client.java 的代码片段被几个函数使用,这些函数由 Philosopher.java 类中的 Threads 调用(fe 在获取远程客户端上的叉子或椅子期间)。要重置所有客户端,我首先停止 Client.java 中的所有线程并加入它们:


来自 Philosopher.java 的片段以停止线程(在 run() 中使用 while(running) 循环

public void terminate() {
    running = false;
}

来自 Client.java 的片段以停止/加入线程

@Override
public void stopClient() throws RemoteException, ServerNotActiveException {
    for (int i = 0; i < threads.size(); i++) {
        log.log( Level.FINE, "{0} temporarily leaving the monastery.", philosophers.get(i).toString());
        try {
            philosophers.get(i).terminate();
            threads.get(i).join();
        } catch (InterruptedException e) {
            log.log(Level.SEVERE, "Couldn't join thread!\n{0}", e);
        }
    }
    log.log( Level.FINE, "Client stopped.");
}

但似乎我无法加入内部线程类中调用 resetClientsForRemoval 的线程。


我的问题:

是否有不同的方法来调用删除函数以将它们与调用线程完全分开?否则它将是一个循环锁,因为我尝试通过在该线程正在执行的函数中调用 join 函数来加入线程。

提前感谢您的所有帮助!

干杯,

斯特凡


如果需要,从 Client.java 重置函数

@Override
public void resetClient(int numberOfChairs, String[] neighbors) throws RemoteException, ServerNotActiveException {
    chairs = new Semaphore [numberOfChairs]; 
    for (int i = 0; i < chairs.length; i++) {
        chairs[i] = new Semaphore(1);
    }
    //generate local forks
    forks = new Semaphore [numberOfChairs];
    for (int i = 0; i < forks.length; i++) {
        forks[i] = new Semaphore(1);
    }
    this.neighbors = neighbors;
    threads = new ArrayList<Thread>();
    for (int i = 0; i < philosophers.size(); i++)
        threads.add(new Thread(philosophers.get(philosophers.size() - 1)));
    int i = 0;
    for (Thread t : threads) {
        log.log(Level.FINE,"{0} entering the updated monastery.", philosophers.get(i).toString());
        t.start();
        i++;
    }
}
4

1 回答 1

0

我在单独的线程中调用 removeClient() 的方法实际上是正确的,但我停止线程的方式却不是。在这种情况下,简单地将运行的布尔值 (while(running)) 设置为 false 并不足以停止每个线程(老实说,我不知道为什么)。在调用 join 之前,我必须调用 thread.interrupt()。现在代码按预期工作=>在另一个线程中启动的线程不会阻止“父”线程中连接的成功执行。

于 2015-12-16T15:14:40.180 回答