我正在使用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生命周期中,我正在循环通过 mynonthreadsafvariable ,然后可能也将循环通过 mynonthreadsafvariable。客户端,然后可能还修改或添加客户端或服务器等…
例如,当服务器连接时,在他的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("")
}
}
所以如果我正确理解为mynonthreadsafevvariable是全局的,那么mynonthreadsafevvariable将是全局的。客户等。
所以我的问题是,在这种情况下,什么是避免竞争条件的好做法?
在访问mynonthreadsafevvariable和mynonthreadsafevvariable时使用互斥锁和同步。客户吗?或者我应该完全避免使用实例变量?但是怎么做呢?
谢谢!
你可以使用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();
}
此外,如果您想避免读锁,您可以复制整个集合并扫描副本,允许在通知时更改原始集合