使用synchronized块的同步队列

时间:2013-02-20 17:05:20

标签: java multithreading sockets synchronization

我想同步我的应用,因为有时服务器会向错误的用户发送消息。我使用synchronized块来同步队列但我的解决方案不起作用 - 有时用户收到的消息不适合他。

这是代码(server.java): (InWorker - 接收来自用户的消息,OutWorker - 向用户发送消息)每个用户都有自己的类(线程) - MiniServer(包含两个线程:InWorkerOutWorker

    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,但有时会将消息发送给错误的用户。为什么?

1 个答案:

答案 0 :(得分:5)

这是一个典型的生产者/消费者场景。丢弃同步块并使用BlockingQueue(InWorker调用put()和OutWorker调用take())。

另外,在您的Server类中,您应该创建一个新的队列 per 连接,而不是在所有连接中共享相同的队列。