我用 Java 撰寫了一個 WebSocket 服務器。這是服務器用來向其客戶端發送 WebSocket 資料包的方法:
private void sendFrame(boolean fin, boolean rsv1, boolean rsv2, boolean rsv3, WebSocketOpcode opcode, byte[] payloadData) throws IOException {
if (connection.isClosed() || webSocketConnectionClosing != null) return;
byte[] header = new byte[2];
if (fin) header[0] |= 1 << 7;
if (rsv1) header[0] |= 1 << 6;
if (rsv2) header[0] |= 1 << 5;
if (rsv3) header[0] |= 1 << 4;
header[0] |= opcode.get() & 0b1111;
header[1] |= payloadData.length < 126 ? payloadData.length : (payloadData.length <= 65535 ? 126 : 127);
out.write(header);
if (payloadData.length > 125) {
if (payloadData.length <= 65535) {
out.writeShort(payloadData.length);
} else {
out.writeLong(payloadData.length);
}
}
out.write(payloadData);
out.flush();
}
這就是我在客戶端連接后宣告輸出流的方式:
out = new DataOutputStream(new BufferedOutputStream(connection.getOutputStream()));
我對此有一些疑問:
上面的代碼是執行緒安全的嗎?我的意思是,多個執行緒可以同時呼叫 sendFrame() 而不會有資料包資料交錯的風險嗎?看起來這段代碼是錯誤的,但我還沒有遇到任何交錯。
如果它不是執行緒安全的,那么我如何在不使用佇列的情況下以這種形式使其成為執行緒安全的?(我希望 sendFrame() 方法在實際發送資料之前一直阻塞)
如果我不將 OutputStream 包裝在 BufferedOutputStream 中,而只包裝在 DataOutputStream 中,這會使 .write() 方法成為原子方法嗎?將整個資料包資料打包到一個單位元組陣列中然后使用該陣列呼叫 .write() 一次是否是執行緒安全的?
uj5u.com熱心網友回復:
上面的代碼是執行緒安全的嗎?我的意思是,多個執行緒可以同時呼叫 sendFrame() 而不會有資料包資料交錯的風險嗎?
它不是執行緒安全的。
看起來這段代碼是錯誤的,但我還沒有遇到任何交錯。
可能發生交織的時間視窗非常小。可能不到一微秒。這意味著它發生的可能性很小。但不是零。
如果它不是執行緒安全的,那么我如何在不使用佇列的情況下以這種形式使其成為執行緒安全的?(我希望 sendFrame() 方法在實際發送資料之前一直阻塞)
這取決于該sendFrame方法如何適合您的其余代碼。
我將使用的方法是確保sendFrame對特定輸出流的所有呼叫并在同一個目標物件上進行。然后我會使用同步來鎖定目標物件或屬于目標物件的私有日志。
另一種方法是使用synchronized并鎖定out. 但是,存在其他事情已經在這樣做的風險,并且sendFrame呼叫將被不必要地阻止。
如果我不包裝
OutputStreaminBufferedOutputStream,而只包裝 in ,DataOutputStream這會使.write()方法原子化嗎?
(這無關緊要。您有 3 個寫呼叫要處理。但是....)
將整個資料包資料打包到一個單位元組陣列中然后
.write()用該陣列呼叫一次是否是執行緒安全的?
這些類都沒有被記錄為1作為執行緒安全的,或者保證write操作是原子的。但是,在 OpenJDK Java 11(至少)中,相關write方法synchronized在BufferedOutputStream和中實作DataOutputStream。
1 - 如果 javadocs沒有指定執行緒安全等特性,那么這些特性可能會因 Java 版本等而異。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/476510.html
