2013-01-12 89 views
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(); 
} 

最终我的问题是非常难问,但上述须藤适当使用线程?即使一次只运行一个线程,它也可以同时从多个其他位置访问。这会造成问题吗?

感谢您的回复。

-William

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

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

    } 

} 
+0

所以在你的例子中,你使用'a'作为线程:'a.start',作为runnable:'c.start(a)'和作为对象:'a.someFunction'。这是令人困惑的,它会帮助发布真实的代码。此外,如果您不确定线程​​是如何工作的,则可以使用易于使用的高级并发包:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService .html – assylias

+0

Ahh我更正了我的sudo示例中的类型,我可以发布实际的代码,但并未全部实现。我确实了解线程是如何工作的,并且经常使用这些线程,当java让我使用上述实现时,以及在我的应用程序中部署这些线程之前,我只是感到惊讶,即时了解是否会有后果。 – user1972748

+0

“在哪个队列中调用一个函数”我认为'a'是一个线程。线程没有功能。 –

回答

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

真棒回复,很多很棒的信息。我想同时解析数据包的原因是能够利用服务器上的多核。当游戏服务器完全加载时(20个连接的客户端为最大/会话),我希望从服务器运行约50个时钟周期(1000包/秒),并且可能接收约1000个包/秒的入站。处理肩膀太糟糕,翻译坐标,检查值,发送字符串等,你认为服务器足够小,可以运行1个线程吗?把它想象成一个20人联盟的传奇服务器即时联盟 – user1972748

0

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

例如,您的数据包侦听器线程可能有一个BlockingQueue它的信息,表明数据包解析器take来自。

0

我认为如果一个套接字(或另一个资源)和每个线程使用该资源的每个调用都会有问题。如果每个调用都使用一个新的(或不同的)套接字,那么我估计不会有问题。来处理这个

的一种方法是同步的访问数:

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

或最好加在somefunction定义

public void synchronized somefunction() { 
    ... 
} 

另一种方式是改变溶液设计同步,与producer-consumer pattern,与没有人访问直接发送给a,但将数据包添加到将被c(消费者)监控的列表中,并发送出现在列表中的每个包。该列表将被同步,但同步将不那么具有侵入性,因为它仅影响将元素添加到列表而不影响元素的所有处理。

更新: 我也建议你的书Java Concurrency In Practice,非常简单的阅读,甚至这次审查从博客The Java Specialists,那是我的书源。