倍增同时访问单个线程

时间:2013-01-12 17:18:19

标签: java multithreading networking

我目前正在使用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是否恰当地使用了线程?即使一次只运行一个线程,也可以同时从多个其他位置访问它。这会引起问题吗?

感谢您的回复。

- 威廉

只需添加编辑以进一步说明。

线程a将是我的数据包发送方,它将数据包从服务器发送到客户端。 线程b将是我的数据包侦听器,它从客户端接收数据包,并将它们发送到线程C(数据包解析器)。 (所以我可以同时解析多个数据包)。 线程c(数据包解析器)可能需要将响应发送回客户端,因此它将调用一个函数,该函数将数据包排队等待发送。

再次感谢,

再次编辑,

使用函数的示例线程

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);

    }

}

3 个答案:

答案 0 :(得分:1)

发送和接收数据包通常很简单,除非您的费率很高,例如10 + K /秒。处理这些数据包可能需要一些时间,但除非这非常昂贵(远远超过解析),我会考虑使用一个线程来完成所有这些功能。它将简化代码并使调试更容易。即使你知道你需要让它变得更复杂,我会尽可能简化设计。

如果你比较上面所用的单线程版本,你可以看到它更简单,这是一个明显的好处,而在这种情况下使用多线程并不是一个明显的好处。

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);
    }
}

答案 1 :(得分:0)

对于与您描述的类似的多线程应用程序,最好使用BlockingQueue在线程之间传递消息。这将自动进行线程安全,并完全按照您使用put(message)take()描述的方式处理消息。

例如,您的数据包侦听器线程可能有BlockingQueueput来自数据包解析器take的消息。

答案 2 :(得分:0)

我认为如果有一个套接字(或其他资源)并且来自每个线程的每个调用都使用该资源,则可能会出现问题。如果每个呼叫使用一个新的(或不同的)套接字,我猜不会有问题。

处理此问题的一种方法是同步访问:

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

或更好地在somefunction定义中添加synchronized

public void synchronized somefunction() {
    ...
}

另一种方法是使用producer-consumer pattern更改解决方案设计,没有人直接访问a,但添加数据包以发送到将由c(消费者)监控的列表,并将发送每个包将出现在列表中。该列表将被同步,但同步将不那么具有干扰性,因为它只会影响将元素添加到列表中而不会影响元素的所有处理。

更新: 我还向您推荐了这本书Java Concurrency In Practice,非常直接的阅读,甚至还有来自博客The Java Specialists的评论,这是本书的来源。