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) {}
}

だから今..私のサーブレットの寿命の間に、私は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 に答える