[英]Java ExecutorService threads writing to same field
首先在這里發布,大家好。 我正在構建一個小型客戶端,該客戶端需要通過套接字發送心跳並通過套接字接收各種固定長度的二進制消息。 我有一個連接管理器類,它啟動套接字連接並創建2個線程,一個線程每x秒發送一次心跳。 另一個線程監聽輸入。
收到輸入后,它將報頭讀入字節數組(始終為4個字節),它得到msg長度x = byte [3],然后將接下來的x個字節讀入消息字節數組。 然后,它使用ExecutorService創建一個新的消息處理程序對象,該對象將接收消息字節數組。
消息處理器實現可運行並打印出消息字節。 但是,如果套接字接收到大量數據,即服務器按順序發送消息,那么我的消息處理器似乎會從不同的線程中打印出混合數據-我認為我的執行者將創建一個新的對象,該對象是線程安全的,並且具有自己的binary []實例。 msgBytes。
connectionManager在其下面創建發送/ rcv線程,rcv線程創建線程池,並在讀取消息時創建新的messageProcessor對象以處理byte []消息
public class connectionManager extends Thread {
public connectionManager(InetAddress host, int serverSocket) {
System.out.println("in connectionManager create");
try {
clientSocket = new Socket(host, serverSocket);
outToServer = new DataOutputStream(clientSocket.getOutputStream());
connected = true;
final ExecutorService executor = Executors.newFixedThreadPool(10);
final Thread inThread = new Thread() {
@Override
public void run() {
while (connected) {
try {
DataInputStream dIn = new DataInputStream(clientSocket.getInputStream());
byte[] header = new byte[4];
dIn.readFully(header); // read the message
String msgType = new String(new byte[]{ header[3] }, "US-ASCII");
short length = getShortFromLittleEndianRange(header, 1); //test function to return length offset is start position of length
byte[] message = new byte[length - 1]; //minus the msg type byte
dIn.readFully(message);
executor.execute(new MessageProcessor(message, msgType));
} catch (Exception e) {
e.printStackTrace();
connected = false;
}
}
executor.shutdown();
System.out.println("Shutdown executor");
};
};
inThread.start();
final Thread outThread = new Thread() {
@Override
public void run() {
Heartbeat hb = new Heartbeat();
while(connected) {
PrintWriter out = null;
try {
this.sleep(3000);
outToServer.write(hb.serialize());
} catch (Exception e) {
e.printStackTrace();
System.out.println("cant send heartbeat server not alive...");
}
}
};
};
outThread.start();
} catch (Exception e) {
System.out.println("Cannot connect to server");
System.exit(0);
}
}
}
MessageProcess實現可運行,我希望執行程序創建新的MessageProcess對象,每個對象都具有自己的msgBytes和msgType實例
public class MessageProcessor implements Runnable {
private byte[] msgBytes;
private String msgType;
MessageProcessor(byte[] newMsgBytes, String newMsgType) {
msgBytes = newMsgBytes;
msgType = newMsgType;
}
@Override
public void run() {
output();
}
synchronized void output() {
System.out.println("\nMessageProcessor process inbound message " + Thread.currentThread().getId());
System.out.println("message type : " + " " + msgType);
for(byte b : msgBytes){
System.out.printf("%02X",b);
}
System.out.println("\nfinished MessageProcessor " + Thread.currentThread().getId());
}
}
但是,當我運行並從服務器接收“大量”的msg消息時,consol輸出看起來好像存在線程安全問題:下面的示例輸出。
MessageProcessor process inbound message 16
message type : 8
01D40806004530515266385779624C6D653830
MessageProcessor process inbound message 17
2D36667664374E6D6A4100000000000000003030515266444E31417A766846000000000000000000000000020000000000A90DAE0400000001000000000000000000000000FA10000000000100000000000000004C43484C4742324500000052D7048024E3F70400BCBDE256306F0100000203003030515266444E31417A766800000000message type : 8
finished MessageProcessor 16
01D50806004530515266385779624C6D6638302D366676643176584A5200000000000000003030515266444E31417A766246000000000000000000000000010000000000A90DAE0400000001000000090000000109000000FA10000000000200000000000000004C43484C4742324500000041D7048024E3F70400BCBDE256306F0100000003003030515266444E31417A766200000000
finished MessageProcessor 17
我希望看到
MessageProcessor process inbound message 16
message type : 8
<hex>
finished MessageProcessor 16
MessageProcessor process inbound message 17
message type : 8
<hex>
finished MessageProcessor 17
我在做自己的事情不安全嗎?
非常感謝Matt
由於您使用的是MessageProcessor
不同實例(每條消息一個),因此output()
上的synchronized
標簽不會產生我認為您期望的效果。 每個實例將能夠訪問其自己的output()
而不被其他實例阻塞。
您看到的輸出是來自不同實例的輸出的混合。 為了防止混淆,您可以使用StringBuilder
構造輸出,然后在一個調用中將其提交給System.out
。 如果要跨實例同步輸出,請考慮使用隊列。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.