0

ソケットとデータ入出力ストリームを使用して、クライアント側とサーバー側で 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 が返されたがまだ開始されていない場合などです。寝るため。sleep(0) でこの問題を回避する方法が本当に思いつかないのですが、誰かアイデアがありますか? それとも、これについて間違った方向に進んでいますか?

本当にありがとう。

4

2 に答える 2

4

LinkedBlockingQueuesを見てください。messagesコード内のおよびnewMessagesオブジェクトの代わりに、これらの 1 つを使用できます。

このクラスを使用すると、あるスレッド A からアイテムを追加し、別のスレッド B から読み取ることができます。スレッド B は、スレッド A によって新しいメッセージが追加されるまで待機します。まさに必要なものです。

于 2012-12-18T11:25:12.657 に答える
0

Runnable をバックグラウンドで実行するために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 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
于 2012-12-18T11:49:25.823 に答える