0

私は現在、データグラムソケット/パケットを介してUDPを使用してJavaでマルチスレッドサーバー/クライアントを構築しています。スレッドの適切な使用法を理解するのに苦労しており、明確にしたいと思います。まず、私がやっていることの例を挙げます。

Thread a;
Thread b(a);

a.start
b.start

//simple enough, now inside b imagine this,
Thread c(a);
if (case)
{
    c.start //therefore I can have a lot of thread c's running at once, 
}

//now inside c imagine this
if (case)
{
    a.somefunction();
}

最終的に私の質問は非常に難しいですが、上記の sudo はスレッドの適切な使用法ですか? 一度に実行されるスレッドは 1 つだけですが、他の複数の場所から同時にアクセスされる可能性があります。これにより問題が発生しますか?

返信ありがとうございます。

-ウィリアム

さらに明確にするために編集を追加するだけです。

スレッド a がパケットの送信者になり、サーバーからクライアントにパケットを送信します。スレッド b がパケット リスナーになり、クライアントからパケットを受信し、パケット パーサーであるスレッド C に送信します。(そのため、複数のパケットを同時に解析できます)。パケット パーサーであるスレッド c は、クライアントに応答を返す必要がある場合があるため、送信するパケットをキューに入れる a の関数を呼び出します。

再度、感謝します、

もう一度編集して、

関数を使用したサンプル スレッド

package server;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Vector;

public class ServerSenderThread extends Thread
{
    DatagramSocket serverSocket;
    Vector<DatagramPacket> outGoingPackets = new Vector<DatagramPacket>();

    public ServerSenderThread(DatagramSocket serverSocket)
    {
        this.serverSocket = serverSocket;
    }

    public void run()
    {
        while (true)
        {
            if (outGoingPackets.size() == 0)
            {
                try
                {
                    Thread.sleep(50);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            else
            {
                try
                {
                    send();
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public void addSend(DatagramPacket packet)
    {
        outGoingPackets.addElement(packet);
    }

    public void send() throws IOException
    {
        DatagramPacket packet = outGoingPackets.get(0);
        outGoingPackets.removeElementAt(0);

        InetAddress address = packet.getAddress();
        int port = packet.getPort();
        byte[] buf = new byte[256];
        String dString = "Data Only the Server Knows";
        buf = dString.getBytes();
        packet = new DatagramPacket(buf, buf.length, address, port);

        System.out.println("Sserver sending packet");   
        serverSocket.send(packet);

    }

}
4

3 に答える 3

1

パケットの送受信は、10 + K /秒などの高速でない限り、一般的に簡単です。これらのパケットの処理には時間がかかる場合がありますが、これが本当に高価でない限り(解析よりもはるかに)、これらすべての機能に1つのスレッドを使用することを検討します。コードが簡素化され、デバッグが容易になります。つまり、もっと複雑にする必要があることがわかっていない限り、デザインはできるだけシンプルにします。

上記のシングルスレッドバージョンを比較すると、はるかに単純であることがわかります。これは明らかな利点ですが、この状況で複数のスレッドを使用することは明確な利点ではありません。

public class DataPacket {
    final DatagramSocket serverSocket;

    public DataPacket(InetAddress address, int port) throws SocketException {
        this.serverSocket = new DatagramSocket(port, address);
    }

    public void send(String message) throws IOException {
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        serverSocket.send(new DatagramPacket(bytes, bytes.length));
        System.out.println("Sent " + message);
    }
}
于 2013-01-12T17:41:21.780 に答える
0

に1つのソケット(または別のリソース)があり、すべてのスレッドからのすべての呼び出しがそのリソースを使用している場合、問題が発生する可能性があると思います。すべての呼び出しで新しい(または異なる)ソケットを使用する場合、問題はないと思います。

これを処理する1つの方法は、アクセスを同期することです。

if (case)
{
    synchronized (a) 
    {
        a.somefunction();
    {
}

または、somefunction定義に同期を追加することをお勧めします

public void synchronized somefunction() {
    ...
}

別の方法は、生産者/消費者パターンを使用してソリューション設計を変更し、誰もaに直接アクセスしないが、c(消費者)によって監視されるリストに送信するパケットを追加し、に表示されるすべてのパッケージを送信することです。リスト。リストは同期されますが、同期はリストへの要素の追加にのみ影響し、要素のすべての処理には影響しないため、煩わしさが少なくなります。

更新:また、「Java Concurrency In Practice 」という本をお勧めします。これは非常に簡単に読むことができます。また、この本のソースであるブログTheJavaSpecialistsからのこのレビューもお勧めします。

于 2013-01-12T17:41:47.693 に答える
0

あなたが説明したものと同様のマルチスレッドアプリケーションの場合、BlockingQueueスレッド間のメッセージパッシングに a を使用するのが最善です。これは自動的にスレッドセーフになり、 と で説明したとおりにメッセージを渡しput(message)ますtake()

たとえば、パケット リスナ スレッドは、パケット パーサーの送信元であるメッセージをBlockingQueue保持できます。puttake

于 2013-01-12T17:32:19.267 に答える