我在应用程序中使用此代码发送一些字符串抛出一个套接字。
public class OutgoingData {
public static DataOutputStream dos = null;
public static String toSend = "";
public static volatile boolean continuousSending = true;
public static String toSendTemp = "";
public static void startSending(final DataOutputStream d) {
new Thread(new Runnable() {
public void run() {
try {
dos = d;
while (continuousSending) {
if (!toSend.equals(toSendTemp)) {
dos.writeUTF(toSend);
dos.flush();
toSendTemp = toSend;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
从另一个线程我称这个方法
private void send(String str) {
OutgoingData.toSend = str;
}
使用此实现可能会出现任何问题吗?除了从两个线程同步调用send()的情况。
我没有使用这样的东西:
private void send(final String str){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (OutgoingData.dos) {
try {
OutgoingData.dos.writeUTF(str);
OutgoingData.dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
因为运行此代码的系统对进程可以创建的线程数有限制,并且需要很长时间来锁定对象。
答案 0 :(得分:1)
您的实现不是线程安全的:
if (!toSend.equals(toSendTemp)) {
// toSend can be changed before this line happens
// causing you to miss data
dos.writeUTF(toSend);
dos.flush();
// or here
toSendTemp = toSend;
}
您需要某种形式的线程同步,无论它是否“慢”。
答案 1 :(得分:1)
更好的选择而不是忙于等待一个字段是使用BlockingQueue<String>
这将确保你永远不会错过一个值,当你无事可做时也不会消耗CPU。
包装队列和线程(池)的一种好方法是使用同时执行这两种操作的ExecutorService。
在您的情况下,Socket流已经是一个队列,因此排队写入另一个队列可能是多余的,您真正需要缓冲输出流。
因为运行此代码的系统对进程可以创建的线程数有限制,并且需要很长时间来锁定对象。
创建线程比创建线程多100倍。理想情况下,你不希望有任何一个。注意:Socket已经有写锁定。