如何在 Java 中的另一个线程内创建一个完全独立的线程?
Posted
技术标签:
【中文标题】如何在 Java 中的另一个线程内创建一个完全独立的线程?【英文标题】:How to create a totally independent Thread inside another Thread in Java? 【发布时间】:2016-03-19 04:23:55 【问题描述】:作为我研究的一部分,我尝试在 Java RMI 中实现一个客户端-服务器软件来解决哲学家就餐问题 (https://en.wikipedia.org/wiki/Dining_philosophers_problem)。
网络必须能够识别意外断开连接(例如崩溃)的客户端并恢复其状态。目前,我的服务器应用程序跟踪网络中的所有客户端(注册新客户端、重置其他客户端以分配椅子),但不跟踪它们的状态。
因此我想使用一个主动系统,一旦其中一个客户端无法连接到另一个客户端,它将使用服务器上的 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 的代码 sn-p 被来自 Philosopher.java 类的 Threads 调用的几个函数使用(例如,在获取远程客户端上的叉子或椅子期间)。要重置所有客户端,我首先停止 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!\n0", 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++;
【问题讨论】:
尚未阅读您的整个问题,但如果您阅读new Thread().start()
,它将完全独立于启动它的线程。
@aioobe 好的,即使这个线程在创建“父”线程上调用 Thread.join?这个连接会等待新创建的线程的执行,还是只是加入它的正常例程,它在创建新线程后进入?我以为是循环锁,因为新线程在其父线程上调用join,而父线程等待新线程完成其工作。
让客户端从您的服务器中删除用户似乎是一个主要的黑客漏洞
@ControlAltDel 是的,确实如此。但幸运的是,我们不必关心这个网络的安全性。因此,这种肮脏的解决方案就足够了。但我绝对宁愿在我的服务器上删除它(不进行轮询)。
如果线程A在线程B上调用join
,那么线程A将等待B终止。 (对 join
的调用将阻塞,直到 B 完成执行。)
【参考方案1】:
我在单独的线程中调用 removeClient() 的方法实际上是正确的,但我停止线程的方式却不是。在这种情况下,简单地将运行的布尔值 (while(running)) 设置为 false 并不足以停止每个线程(老实说,我不知道为什么)。在调用 join 之前,我必须调用 thread.interrupt()。现在代码按预期工作 => 在另一个线程中启动的线程不会阻止在“父”线程中成功执行连接。
【讨论】:
以上是关于如何在 Java 中的另一个线程内创建一个完全独立的线程?的主要内容,如果未能解决你的问题,请参考以下文章