我有一台服务器从客户端接收各种xml消息(每个客户端一个线程),并根据消息类型将消息路由到不同的函数。例如。如果消息中的第一个元素包含字符串'login',则表示这是一个登录消息,因此将消息路由到login()函数。
无论如何,我想发布此消息,以便在连接多个客户端并且调度程序在消息路由中间切换线程时,事情不会搞砸。所以这就是我如何路由消息 -
public void processMessagesFromClient(Client client)
{
Document message;
while (true)
{
try
{
message = client.inputStream.readObject();
/*
* Determine the message type
*/
String messageType = getMessageType(message);
// Route the message depending on its type
switch (messageType)
{
case LOGIN:
userModel.handleLogin();
...
...
...
etc...
}
} catch(Exception e) {}
}
那么我怎样才能使这个线程安全?我想我需要在某个地方放一个同步语句,但我不知道在哪里。我也一直在阅读这个主题,我发现这篇文章说在'this'上使用同步有一个问题 - https://stackoverflow.com/a/416198/1088617
此处的另一篇文章称单例不适合使用同步(上面代码中的我的类是单例) - https://stackoverflow.com/a/416202/1088617
答案 0 :(得分:2)
我实际上有一个消息处理程序线程,它负责读取传入的消息。然后,这将处理切换到工作线程以执行消息的耗时处理。您可以使用Java ThreadPoolExecutor来管理它。
答案 1 :(得分:2)
您的类已经线程安全,因为您只使用局部变量。 线程安全仅在您访问类 state (即字段)时才会发挥作用,而您的代码似乎没有(似乎)这样做。
您所谈论的是序列化 - 您希望通过一个点汇集所有消息处理,以保证消息处理是一次一个(开始和完成原子< / em>的)。解决方案很简单:使用static synchronized
方法:
public void processMessagesFromClient(Client client) {
Document Message;
while (true) {
processMessage(client);
}
}
private static synchronized processMessage(Client client) {
try {
message = client.inputStream.readObject();
String messageType = getMessageType(message);
// Route the message depending on its type
switch (messageType) {
case LOGIN:
userModel.handleLogin();
...
etc...
}
} catch(Exception e) {}
}
FYI static synchronized
方法使用Class对象作为锁。此代码将使您的代码行为像单个线程,您的问题似乎需要。
答案 2 :(得分:1)
如果每个线程都有这些对象之一,则没有问题。您只需要同步一个可由其中一个线程修改的共享对象。
public void processMessagesFromClient(Client client) {
while (true) {
processMessage(client);
}
}
private void processMessage(Client client) {
try {
Document message = client.inputStream.readObject();
String messageType = getMessageType(message);
// Route the message depending on its type
switch (messageType) {
case LOGIN:
userModel.handleLogin();
...
etc...
}
} catch(Exception e) {}
}
答案 3 :(得分:1)
如果每个连接已有1个线程,则必须同步的唯一事情是处理事件的函数(即userModel.handleLogin()
等函数)。
答案 4 :(得分:1)
我想最好的解决方案应该是使用一个类似ConcurrentQueue的线程安全队列,并使用一个工作线程来获取这些值并逐个运行这些操作。
答案 5 :(得分:0)
您需要知道哪个资源应该只在某个时间使用一个线程。
在您的情况下,阅读下一条消息可能需要受到保护。
synchronize (lock) {
message = client.inputStream.readObject();
}
但是,您的代码示例并未真正显示需要防止并发访问的内容
答案 6 :(得分:0)
该方法本身是线程安全的。
但是,请注意您的类是单身,您可能希望在double checked locking
中使用getInstance
来确保线程安全。
此外,您应确保将您的实例设置为static
class Foo {
private static volatile Foo instance = null;
public static Foo getInstance() {
if (instance == null)
{
synchronized(this)
{
if (instance == null)
instance = new Foo ();
}
}
return instance ;
}
}