处理Java套接字并发
我正在构建一个服务器,每2秒通过一个TCP套接字为每个用户发送一次数据,并在一个单独的线程上发送。偶尔也会有一些特殊事件和常规数据一起发送。有时,多个数据包中的数据会混淆,所以我创建了一个队列以确保它不会发生。然而,问题仍然存在,我的方法是否不正确,或者我的代码是否有问题处理Java套接字并发,java,sockets,concurrency,Java,Sockets,Concurrency,我正在构建一个服务器,每2秒通过一个TCP套接字为每个用户发送一次数据,并在一个单独的线程上发送。偶尔也会有一些特殊事件和常规数据一起发送。有时,多个数据包中的数据会混淆,所以我创建了一个队列以确保它不会发生。然而,问题仍然存在,我的方法是否不正确,或者我的代码是否有问题 protected void sendData (byte[] data) { if (isSendingData) { dataQueue.add(data);
protected void sendData (byte[] data) {
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
Thread sendThread = new Thread() {
public void run () {
try {
BufferedOutputStream outStream = new BufferedOutputStream(connectionSocket.getOutputStream());
outStream.write(data);
outStream.flush();
// check queue, if there are data, send
byte[] moreData = null;
if (dataQueue.size() > 0) {
moreData = dataQueue.remove(0);
}
isSendingData = false;
if (moreData != null) {
sendData(moreData);
}
}
catch (Exception e) {
System.out.println ("Error sending data to peripheral: " + e);
isSendingData = false;
}
}
};
sendThread.start ();
}
使用队列消除并发性问题的正确习惯用法是让一个长寿命线程运行一个无限循环,该循环从队列中获取元素并处理它们。通常,您将使用一个阻塞队列,以便在每次迭代中线程进入睡眠状态,直到有一个项目要处理 您的解决方案在许多方面都与上述方案不同。例如:
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
-如果同时调用此方法,这将导致争用条件:两个线程都可以将isSendingData
读取为false,然后通过网络并发地发送数据。如果isSendingData
不是volatile
,那么它也有一个数据竞争(与上面解释的竞争条件完全不同)
-这是另一个争用条件:在将大小读取为零后,另一个线程可以向队列中添加一个项目。现在,该项目可能永远不会被处理。它将在队列中逗留,直到另一个这样的线程启动
更明显的是,您的解决方案不正确,因为您启动的线程没有循环,只处理一条消息,还可能处理队列中的一条额外消息。这应该重新处理,以便没有特殊情况,
sendData
总是无条件地提交到队列,并且从不单独发送任何数据。使用队列消除并发问题的正确习惯用法是让一个长寿命线程运行一个无限循环,从队列中提取元素并处理它们。通常,您将使用一个阻塞队列,以便在每次迭代中线程进入睡眠状态,直到有一个项目要处理
您的解决方案在许多方面都与上述方案不同。例如:
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
-如果同时调用此方法,这将导致争用条件:两个线程都可以将isSendingData
读取为false,然后通过网络并发地发送数据。如果isSendingData
不是volatile
,那么它也有一个数据竞争(与上面解释的竞争条件完全不同)
-这是另一个争用条件:在将大小读取为零后,另一个线程可以向队列中添加一个项目。现在,该项目可能永远不会被处理。它将在队列中逗留,直到另一个这样的线程启动
更明显的是,您的解决方案不正确,因为您启动的线程没有循环,只处理一条消息,还可能处理队列中的一条额外消息。这应该重新处理,以便没有特殊情况,
sendData
总是无条件地提交到队列,并且从不单独发送任何数据。使用队列消除并发问题的正确习惯用法是让一个长寿命线程运行一个无限循环,从队列中提取元素并处理它们。通常,您将使用一个阻塞队列,以便在每次迭代中线程进入睡眠状态,直到有一个项目要处理
您的解决方案在许多方面都与上述方案不同。例如:
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
-如果同时调用此方法,这将导致争用条件:两个线程都可以将isSendingData
读取为false,然后通过网络并发地发送数据。如果isSendingData
不是volatile
,那么它也有一个数据竞争(与上面解释的竞争条件完全不同)
-这是另一个争用条件:在将大小读取为零后,另一个线程可以向队列中添加一个项目。现在,该项目可能永远不会被处理。它将在队列中逗留,直到另一个这样的线程启动
更明显的是,您的解决方案不正确,因为您启动的线程没有循环,只处理一条消息,还可能处理队列中的一条额外消息。这应该重新处理,以便没有特殊情况,
sendData
总是无条件地提交到队列,并且从不单独发送任何数据。使用队列消除并发问题的正确习惯用法是让一个长寿命线程运行一个无限循环,从队列中提取元素并处理它们。通常,您将使用一个阻塞队列,以便在每次迭代中线程进入睡眠状态,直到有一个项目要处理
您的解决方案在许多方面都与上述方案不同。例如:
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
-如果同时调用此方法,这将导致争用条件:两个线程都可以将isSendingData
读取为false,然后通过网络并发地发送数据。如果isSendingData
不是volatile
,那么它也有一个数据竞争(与上面解释的竞争条件完全不同)
-这是另一个争用条件:在将大小读取为零后,另一个线程可以向队列中添加一个项目。现在,该项目可能永远不会被处理。它将在队列中逗留,直到另一个这样的线程启动
更明显的是,您的解决方案不正确,因为您启动的线程没有循环,只处理一条消息,还可能处理队列中的一条额外消息。这应该重新处理,以便没有特殊情况,
sendData
始终无条件地提交到队列,并且从不单独进行任何发送。我会完全不同地执行此操作。您不希望在应用程序中出现任意长的队列
- 发送心跳信号时,让hearbeat线程在套接字上同步
- 不要让它发送任何其他东西
- 除掉