Java发送消息线程

时间:2012-12-18 11:21:16

标签: java multithreading sockets dataoutputstream

我用Java编写了一个游戏,客户端和服务器端使用套接字和数据输入/输出流。服务器端有时需要在“for”循环中向所有用户发送消息,但由于写入套接字可以阻止我为每个向其发送消息的用户创建了一个线程(以及为每个用户监听的另一个线程)传入的消息)。发送线程建立在这个想法上:

private ArrayList<Object> messages = new ArrayList<Object>(),
                          newMessages = new ArrayList<Object>();

public void run() {
    while (true) {
        for (Object message: messages) {
            try {
                if (message instanceof Byte)
                    out.writeByte((Byte)message);
                else if (message instanceof Boolean)
                    out.writeBoolean((Boolean)message);
                else if (message instanceof String)
                    out.writeUTF((String)message);
                else if (message instanceof Integer)
                    out.writeInt((Integer)message);
                else if (message instanceof Long)
                    out.writeLong((Long)message);
            } catch (IOException e) {}
        }
        synchronized (newMessages) {
            messages.clear();
            messages.addAll(newMessages);
            newMessages.clear();
        }
    }
}

public void write(Object message) {
    synchronized (newMessages) {
        newMessages.add(message);
    }
}

不幸的是run()方法一直在运行,所以我想插入一个sleep命令来实现这样的目的:

private ArrayList<Object> messages = new ArrayList<Object>(),
                          newMessages = new ArrayList<Object>();

public void run() {
    while (true) {
        try {
            if (messages.isEmpty() && newMessages.isEmpty())
                sleep(0);
        } catch (InterruptedException e) {}
        for (Object message: messages) {
            try {
                if (message instanceof Byte)
                    out.writeByte((Byte)message);
                else if (message instanceof Boolean)
                    out.writeBoolean((Boolean)message);
                else if (message instanceof String)
                    out.writeUTF((String)message);
                else if (message instanceof Integer)
                    out.writeInt((Integer)message);
                else if (message instanceof Long)
                    out.writeLong((Long)message);
            } catch (IOException e) {}
        }
        synchronized (newMessages) {
            messages.clear();
            messages.addAll(newMessages);
            newMessages.clear();
        }
    }
}

public void write(Object message) {
    synchronized (newMessages) {
        newMessages.add(message);
        interrupt();
    }
}

但是当有要发送的消息时,这可能导致线程进入休眠状态,例如在run()方法调用isEmpty()之后调用write()方法时,返回true,但是还没开始睡觉我真的想不出一种方法来避免这个问题与睡眠(0),有没有人有一个想法?或者我对此采取了错误的方式?

非常感谢。

2 个答案:

答案 0 :(得分:4)

看看LinkedBlockingQueues。您可以在代码中使用其中一个而不是messagesnewMessages个对象。

此类允许您从一个线程A添加项目并从另一个线程B读取。线程B将等待,直到线程A添加新消息。应该正是您所需要的。

答案 1 :(得分:0)

我会重新考虑您的解决方案,使用ScheduledExecutorService在后台执行Runnable。该类还允许以固定速率执行定期操作:

您的Runnable类:

public void run() {
    for (Object message: messages) {
        try {
            if (message instanceof Byte)
                out.writeByte((Byte)message);
            else if (message instanceof Boolean)
                out.writeBoolean((Boolean)message);
            else if (message instanceof String)
                out.writeUTF((String)message);
            else if (message instanceof Integer)
                out.writeInt((Integer)message);
            else if (message instanceof Long)
                out.writeLong((Long)message);
        } catch (IOException e) {}
    }
    synchronized (newMessages) {
        messages.clear();
        messages.addAll(newMessages);
        newMessages.clear();
    }

}

public void write(Object message) {
    synchronized (newMessages) {
        newMessages.add(message);
    }
}

然后,用于调用Runnable:

  Runnable sender=new MyMessageSender(); //or whatever your class is called

  int threadPoolSize=1; //number of Threads you want to launch
  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(threadPoolSize);

  final ScheduledFuture<?> senderHandle =
       scheduler.scheduleAtFixedRate(sender, 10, 10, SECONDS); //from now in 10 senconds, execute sender every 10 seconds