【发布时间】:2016-03-23 19:23:20
【问题描述】:
我正在尝试编写一种方法,该方法向设备询问输入然后接受响应,所有这些都是原子操作。
这是我的代码(query 方法确实应该重点关注):
public class DeviceConnection implements Runnable{
//For query
static int test = 0;
//For writeline
static PrintWriter out = null; //(initialized in constructor)
//Only important for readline
static String[] systemMessage=new String[10];
static int messageIn=0;
static int messageOut=0;
static boolean connected = false;
static boolean endConnect = true;
static PrintStream logWriter; //(initialized in constructor)
static String serverName="";//(initialized in constructor)
static int socketNum;//(initialized in constructor)
/** REALLY ONLY NEED TO LOOK AT THIS METHOD
* Atomic operation to ask for data from device
* and get a response.
* @param line - query to be passed to device
* @return response from device
*/
public synchronized String query(String line){
int temp = test;
System.err.print("foo" + test);
System.err.print(this);
String response;
writeLine(line);
response = readLine();
System.err.println("bar" + test + " should be " + temp);
test = temp+1;
return response;
}
/**
* Writes a query to the device.
*<p>
* Does <b>not</b> get or handle any response
* @param line - query to be passed to device
*/
public synchronized void writeLine(String line) {
out.println(line + "\n");
}
/**
* Reads a response from device.
*<p>
* Should never be used outside of <code>query</code>
* as this could create a race condition if another
* thread is writing to the device at the same time.
* @return
*/
private synchronized String readLine() {
String response;
long start, stop;
if (messageIn != messageOut) { // new message exists
response = systemMessage[messageOut];
messageOut = (messageOut + 1) % 10;
} else {
start = System.currentTimeMillis();
try {
if (connected) { // if connected wait for heatbeats
//wait(15000);
wait();
start = System.currentTimeMillis();
} else { // if not connected ignore heartbeats
wait();
start = System.currentTimeMillis();
}
} catch (InterruptedException e) { return "Interrupted"; }
stop = System.currentTimeMillis();
if (stop - start < 12000) { // heart beats running at 5 s
if (messageIn != messageOut) { // new message exists
response = systemMessage[messageOut];
messageOut = (messageOut + 1) % 10;
} else {
return null;
}
} else { // heart beats lost
response = "Heart beats lost";
logWriter.println(response);
if (connected) { // connection lost on client side
logWriter.println("Connection to " + serverName +
" lost on client side");
sleep(60000);
connect(serverName,socketNum);
}
}
}
return response;
}
}
通常query 方法运行良好,但有时我会得到如下输出:
foo59lib.DeviceConnection@7bd0bf6d(other System.out stuff printed here)
foo59lib.DeviceConnection@7bd0bf6dbar59 should be 59
bar60 should be 59
这怎么可能?方法不是在对象上锁定/同步吗?该对象显然与打印显示的相同,但不知何故同时执行了两个 query 方法。
【问题讨论】:
-
你有多少个 DeviceConnection 类的实例?
-
其实是一个单例类,所以只有一个。然而,这甚至不重要,因为输出清楚地表明这两种方法都是从同一个对象调用的(使用 id:
DeviceConnection@7bd0bf6d)
标签: java multithreading thread-safety synchronized