我正在玩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时使用互斥并对它们进行同步?或者我应该避免使用实例变量?但是如何?
谢谢!
答案 0 :(得分: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();
}
此外,如果您想避免读取锁定,您可以复制整个集合并扫描副本,以便在通知时更改原始集合的可能性。