2012-12-18 150 views
0

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

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()方法是不断运行的,所以我想插入一个睡眠命令,来实现这样的事情:

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)这个问题,有没有人有想法?或者我对此有错误的看法?

谢谢你一堆。

回答

4

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

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

+0

是的,正是我需要的。你真棒,非常感谢! –

+0

@AlebreExobrum:如果你喜欢我的回答,你应该可以接受它:) – Simon

0

我会重新考虑您的解决方案,使用ScheduledExecutorService在后台执行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