[英]Strange java behavior with while loop and queue
I have strange behavior of while(true) loop. 我有while(true)循环的奇怪行为。 Here is the code:
这是代码:
As a member of class I have: 作为班级成员,我有:
static Queue<Object> response = new LinkedList<Object>();
... and a function: ......和一个功能:
private void read() {
while (true)
{
System.out.println("foo");
if(!(response.isEmpty()))
{
if((Boolean)response.peek() == true)
{
view.dispose();
LogInControler controler= new LogInControler();
disableMasterLogin();
response.poll();
return;
}
else if((Boolean)response.poll() == false)
{
JOptionPane.showMessageDialog(view.getRootPane(),
"Wrong username or password.");
view.tfUsername.requestFocus();
return;
}
}
}
}
When object is received from server(via Socket), InputController class pass that object to appropriate controller, in this case MasterLogInController and put it in Queue response. 当从服务器接收对象(通过Socket)时,InputController类将该对象传递给适当的控制器,在本例中为MasterLogInController并将其放入Queue响应中。 I am waiting for that response in while(true) loop, but the problem is if I remove "System.out.printline("foo");"
我在while(true)循环中等待响应,但问题是如果我删除“System.out.printline(”foo“);” loop will be entered only once!?
循环只会输入一次!? With this syso line I "force" while loop to do loops until response is received.
使用这个syso行,我“强制”while循环执行循环,直到收到响应。 What's wrong here?
这有什么不对?
I assume you have several threads running. 我假设你有几个线程在运行。
System.out.println
creates a memory barrier which probably helps your code see some variable which is otherwise not visible (because of lack of synchronization). System.out.println
创建了一个内存屏障,可能会帮助您的代码看到一些不可见的变量(因为缺少同步)。
In particular, your queue is not thread safe and does seem to be safely published. 特别是,您的队列不是线程安全的,似乎安全发布。 So it is very conceivable that:
因此可以想象:
while
loop might see response
as null ==> NullPointerException while
循环可能会看到response
为null ==> NullPointerException reponse.isEmpty()
might return false but response.peek()
might return null, which you then cast to a Boolean
and unbox in your condition if((Boolean)xxx == true)
==> NullPointerException reponse.isEmpty()
可能返回false,但是response.peek()
可能会返回null,然后在你的条件下转换为Boolean
和unbox if((Boolean)xxx == true)
==> NullPointerException Apart from the sound advice given in the comments to help understand the cause, you should make the code thread safe. 除了评论中给出的有助于理解原因的合理建议之外,您还应该使代码线程安全。 For example, you could use a thread safe BlockingQueue .
例如,您可以使用线程安全的BlockingQueue 。 But that will probably not be enough (because of the way your various if / if / else if statements are laid out and the fact that the queue might be changed by another thread between each of those statements).
但这可能还不够(因为你的各种if / if / else if语句的布局方式以及队列可能被每个语句之间的另一个线程更改的事实)。
I suspect what is happening is that your loop is being optimised out of existence by the JIT compiler. 我怀疑正在发生的事情是你的循环被JIT编译器优化了。 If
response.isEmpty()
is true the first time it is called in your loop, and noticing that response
is not inside a synchronized
block or method, or marked volatile
, it is likely the JIT compiler will decide that it's not going to change and just remove what appears to be an empty busy loop from running code. 如果第一次在循环中调用
response.isEmpty()
为true,并注意到response
不在synchronized
块或方法中,或者标记为volatile
,则JIT编译器可能会认为它不会更改并且从运行代码中删除看似空忙的循环。
Adding in the println()
statement at least gives the loop a purpose, in the eyes of the JIT compiler, so it will leave it running in that case. 在JIT编译器的眼中,添加
println()
语句至少给出了循环的目的,因此在这种情况下它将保持运行。
To fix this, in addition to the salient advice given by assylias, you can put all references to response
inside a synchronized
block like so: 要解决这个问题,除了assylias给出的显着建议之外,你可以将所有对
response
引用放在synchronized
块中,如下所示:
public void read() {
Boolean result = null;
synchronized (response) {
while (true) {
result = (Boolean) response.poll();
if (result != null) break;
try {
response.wait();
} catch (InterruptedException e) {
e.printStackTrace();
// You could put return; here
}
}
}
// result should always be non null here
if (result) {
view.dispose();
LogInControler controler = new LogInControler();
disableMasterLogin();
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(view.getRootPane(), "Wrong username or password");
view.tfUsername.requestFocus();
}
});
}
}
Where your other thread is adding the response to the queue, make sure that is also in an synchronized block and calls notifyAll()
: 如果您的其他线程正在将响应添加到队列,请确保它也在同步块中并调用
notifyAll()
:
public void addResult(Object result) {
synchronized (response) {
response.add(result);
response.notifyAll();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.