我想同步我的应用,因为有时服务器会向错误的用户发送消息。我使用synchronized块来同步队列但我的解决方案不起作用 - 有时用户收到的消息不适合他。
这是代码(server.java):
(InWorker - 接收来自用户的消息,OutWorker
- 向用户发送消息)每个用户都有自己的类(线程) - MiniServer
(包含两个线程:InWorker
和OutWorker
)
class InWorker implements Runnable{
String slowo=null;
ObjectOutputStream oos;
ObjectInputStream ois;
ConcurrentMap<String,LinkedBlockingQueue<Message>> map=new ConcurrentHashMap<String, LinkedBlockingQueue<Message>>();
Message message=null;
InWorker(ObjectInputStream ois,ConcurrentMap<String,LinkedBlockingQueue<Message>> map) {
this.ois=ois;
this.map=map;
}
public void run() {
while(true) {
//synchronized(queue) {
try {
message = (Message) ois.readObject();
slowo=message.msg;
if(slowo!=null && !slowo.equals("Bye")) {
if(!map.containsKey(message.id)) {
map.putIfAbsent(message.id, new LinkedBlockingQueue<Message>());
try {
map.get(message.id).put(message);
} catch (InterruptedException ex) {
Logger.getLogger(Communicator.class.getName()).log(Level.SEVERE, null, ex);
}
}
else
{
try {
map.get(message.id).put(message);
} catch (InterruptedException ex) {
Logger.getLogger(Communicator.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//}
Thread.yield();
}
}
}
class OutWorker implements Runnable{
String tekst=null;
ObjectOutputStream oos=null;
String id;
Message message;
ConcurrentMap<String,LinkedBlockingQueue<Message>> map=new ConcurrentHashMap<String, LinkedBlockingQueue<Message>>();
OutWorker(ObjectOutputStream oos,String id,ConcurrentMap<String,LinkedBlockingQueue<Message>> map) {
this.oos=oos;
this.id=id;
this.map=map;
}
public void run() {
while(true) {
//synchronized(queue) {
if(map.containsKey(id)) {
while(!map.get(id).isEmpty()) {
try {
message=map.get(id).take();
} catch (InterruptedException ex) {
Logger.getLogger(OutWorker.class.getName()).log(Level.SEVERE, null, ex);
}
try {
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//}
Thread.yield();
}}}
这是MiniServer和Server类:
class MiniSerwer implements Runnable{
Socket socket=null;
ExecutorService exec=Executors.newCachedThreadPool();
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
String id;
Queue<Message> queue=new LinkedList<Message>();
MiniSerwer(ObjectOutputStream oos,ObjectInputStream ois,String id,Queue<Message> queue) {
this.oos=oos;
this.ois=ois;
this.id=id;
this.queue=queue;
}
public void run() {
exec.execute(new InWorker(ois,queue)); // input stream
exec.execute(new OutWorker(oos,id,queue)); //output stream
Thread.yield();
}
}
public class Serwer implements Runnable{
ServerSocket serversocket=null;
ExecutorService exec= Executors.newCachedThreadPool();
int port;
String id=null;
Queue<Message> queue=new LinkedList<Message>();
BufferedReader odczyt=null;
ObjectInputStream ois=null;
Message message=null;
ObjectOutputStream oos=null;
Serwer(int port) {
this.port=port;
}
public void run() {
try {
serversocket=new ServerSocket(port);
while(true) {
Socket socket=null;
try {
socket = serversocket.accept();
/* first message is login*/
oos=new ObjectOutputStream(socket.getOutputStream());
oos.flush();
ois=new ObjectInputStream(socket.getInputStream());
message = (Message) ois.readObject();
id=message.sender;
System.out.println(id+" log in to the server");
exec.execute(new MiniSerwer(oos,ois,id,queue)); // create new thread
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int port;
port=8821;
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new Serwer(port));
}
任何人都可以帮助我吗?
编辑:我将队列更改为ConcurrentHashMap,但有时会将消息发送给错误的用户。为什么?
答案 0 :(得分:5)
这是一个典型的生产者/消费者场景。丢弃同步块并使用BlockingQueue
(InWorker调用put()
和OutWorker调用take()
)。
另外,在您的Server类中,您应该创建一个新的队列 per 连接,而不是在所有连接中共享相同的队列。