这是我第一次在java中使用线程,我遇到了一些奇怪的问题。
public class ServerSender implements Runnable {
DatagramSocket udpSocket;
DatagramPacket sendPacket;
long currentTime = 0;
long elapsed = 0;
public ServerSender(DatagramSocket udpSocket) {
this.udpSocket = udpSocket;
System.out.println("Sender live!");
}
public void sendToClient(byte[] bytes) throws IOException {
sendPacket = new DatagramPacket(bytes, bytes.length, Server.clientIp, Server.clientPort);
udpSocket.send(sendPacket);
}
@Override
public void run() {
while(true)
{
if(Server.isGameLive)
{
currentTime = System.nanoTime();
if(elapsed / 1000000 >= 100) // send snapshot every 100ms
{
synchronized(Server.snapshot)
{
try
{
sendToClient(Server.snapshot.toByteArray());
}
catch (IOException e)
{
e.printStackTrace();
}
}
elapsed = 0;
System.out.println("Sending snapshot to client...");
} else {
System.out.println("not elapsed");
}
elapsed += System.nanoTime() - currentTime;
System.out.println(elapsed / 1000000);
} else {
System.out.println("not live");
}
}
}
}
此代码的工作原理应该如何,但是当我从run方法中删除else语句时,它无法运行...
@Override
public void run() {
while(true)
{
if(Server.isGameLive)
{
currentTime = System.nanoTime();
if(elapsed / 1000000 >= 100) // send snapshot every 100ms
{
synchronized(Server.snapshot)
{
try
{
sendToClient(Server.snapshot.toByteArray());
}
catch (IOException e)
{
e.printStackTrace();
}
}
elapsed = 0;
System.out.println("Sending snapshot to client...");
}
elapsed += System.nanoTime() - currentTime;
System.out.println(elapsed / 1000000);
}
}
}
有人可以解释那里有什么问题吗?
答案 0 :(得分:3)
我完全疯狂的猜测是你正在读取你在另一个线程中被更改的非易失性值。
当您读取非易失性字段时,JIT可以自由内联该值,因此它可能永远不会看到您将其更改为的值。
但是,如果你放慢循环,例如通过写入控制台,它可能无法运行足够的时间进行JIT,因此您不会看到此优化,并且循环会按预期停止。
http://vanillajava.blogspot.com/2012/01/demonstrating-when-volatile-is-required.html
答案 1 :(得分:0)
首先,请确保Server.isGameLive
不稳定,因此您不会遇到内存可见性问题。
使用此代码,您测量的代码片段可能比使用System.nanoTime()的分辨率花费更少的时间。
你的时间计算应该是这样的:
public void run() {
currentTime = System.nanoTime();
while(true) {
if(Server.isGameLive) {
if(elapsed / 1000000 >= 100) {
synchronized(Server.snapshot) {
try {
sendToClient(Server.snapshot.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
}
elapsed = 0;
currentTime = System.nanoTime();
System.out.println("Sending snapshot to client...");
}
elapsed = System.nanoTime() - currentTime;
System.out.println(elapsed / 1000000);
}
}
}
答案 2 :(得分:0)
我认为已移除println
会使操作稍微减慢,因此您可以在循环结束时添加Thread.sleep(1);
。
这样不仅可以防止出现此问题,还可以让其他线程使用CPU。