2013-01-12 123 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,那是我的書源。