0

我正在玩 WebSocketServlet (tomcat),我有一些关于在没有竞争条件问题的情况下正确执行它的问题。

我有一个实例变量(非线程安全),它将跟踪所有 websocket 连接

HashMap<String,MyServers> myNonThreadSafeVariable = HashMap<String,MyServers>

这就是 HashMap 将包含的内容(大致......)

private final class MyServers extends MessageInbound {
       final Set<MyClients> clients = new CopyOnWriteArraySet<MyClients>();
       private String serverName; 

      @Override
      protected void onOpen(WsOutbound outbound) {}

      @Override
      protected void onClose(WsOutbound outbound) {}

      @Override
      protected void onText(WsOutbound outbound) {}
}

private final class Clients extends MessageInbound {

       private int clientID; 


      @Override
      protected void onOpen(WsOutbound outbound) {}

      @Override
      protected void onClose(WsOutbound outbound) {}

      @Override
      protected void onText(WsOutbound outbound) {}
}

所以现在.. 在我的 servlet 生命周期中,我正在循环通过myNonThreadSafeVariable,然后可能还会循环通过myNonThreadSafeVariable.clients,然后可能还会修改或添加客户端服务器等...

例如,当服务器连接时,在他的 onOpen 中会有类似

myNonThreadSafeVariable.put(key,this);

或者当客户在他的 onOpen 中连接时(不要担心这个)

server = myNonThreadSafeVariable,get(key);
sever.clients.add(this);

或者有时当我必须 ping 所有服务器的所有客户端时:

for (Entry<String, MyServers> entry : myNonThreadSafeVariable.entrySet()) {

   MyServers server = entry.getValue();
   server.sendMessage("ping||");

   for (MyClients member : entry.getValue().clients) {
      client.sendMessage("")
   }
}

因此,如果我正确理解 myNonThreadSafeVariable 是全局的,那么 myNonThreadSafeVariable.clients 等也会如此。

所以我的问题是在这种情况下避免竞争条件的好习惯是什么?

在访问 myNonThreadSafeVariable 和 myNonThreadSafeVariable.clients 时使用互斥锁并对其进行同步?还是我应该完全避免使用实例变量?但是如何?

谢谢 !

4

1 回答 1

0

您可以使用ReadWriteLock:在写入时阻止读者和作者,在阅读时仅阻止作者:

private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
...
writeLock.lock();
try
{
    myNonThreadSafeVariable.put(key,this);
}
finally
{
    writeLock.unlock();
}
...
writeLock.lock();
try
{
    server = myNonThreadSafeVariable,get(key);
    sever.clients.add(this);
}
finally
{
    writeLock.unlock();
}
...
readLock.lock();
try
{
    for (Entry<String, MyServers> entry : myNonThreadSafeVariable.entrySet())
    {
        MyServers server = entry.getValue();
        server.sendMessage("ping||");

        for (MyClients member : entry.getValue().clients)
        {
            client.sendMessage("")
        }
    }
}
finally
{
    readLock.unlock();
}

此外,如果您想避免读取锁定,您可以复制整个集合并扫描副本,从而在通知的同时更改原始集合的可能性。

于 2013-06-16T13:40:25.637 回答