有没有人知道为什么这样看起来只会退出如果是一个System.out.println()?
如果我注释掉println()
,那么相同的代码就不起作用了do{
System.out.println("");
if(hasWon()){
InOut.out(output() + "\nYou Won");
System.exit(0);
}
} while (!hasWon())
该计划如下
static final int gridSize = Integer.parseInt(InOut.in(1, "Enter grid size"));
static Tile[][] board = new Tile[gridSize][gridSize];
static int winCond = 1;
static GuiFrame f = new GuiFrame(gridSize);
static BtnPanel p = new BtnPanel(gridSize);
static JButton[][] btn = new JButton[gridSize][gridSize];
public static void main(String[] args) {
//Creating objects
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
board[i][z] = new Tile();
}
}
GUI();
while (!hasWon()) {
System.out.println("");
if(hasWon()){
InOut.out(output() + "\nYou Won");
System.exit(0);
}
}
}
public static boolean hasWon() {
boolean hasWon = true;
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
hasWon = hasWon && (board[i][z].getStatus() == winCond);
}
}
return hasWon;
}
public static String output() {
String message = "";
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
message += board[i][z].getStatus() + " ";
}
message += "\n";
}
return message;
}
public static void GUI() {
for (int i = 0; i < gridSize; i++) {
for (int z = 0; z < gridSize; z++) {
String btnValue = "";
btnValue += board[i][z].getStatus();
btn[i][z] = new JButton();
btn[i][z].setText(btnValue);
btn[i][z].addActionListener(f);
p.add(btn[i][z]);
}
}
f.add(p, BorderLayout.CENTER);
}
public static void modifyGUI(int i, int z){
btn[i][z].setText(String.valueOf(board[i][z].getStatus()));
}
这是一款益智游戏,用户点击图块,相邻的图块也会发生变化。但是当拼图完成后,如果没有println()它就不会显示完成,使用println()它会退出循环并退出程序。
重新强调,如果while循环中有println(),一切正常。当我发表评论时,它无法正常工作。
答案 0 :(得分:2)
你所拥有的是一个密集的CPU密集型循环,它反复调用hasWon()
。它看起来像其他一些线程负责更新电路板状态,导致&#34;赢得&#34;位置。
看起来问题是紧凑的CPU循环导致另一个线程饿死,插入println
就足以让线程调度程序重新安排。
另一种可能的解释是,您有一个共享数据结构,一个线程正在读取而另一个正在更新... 没有任何同步。从理论上讲,您不进行同步这一事实可能意味着更新线程所做的更改从未被读取线程看到,因为编译器没有看到需要插入&#34;屏障&#34;指令将导致相关的缓存刷新等。
正如@chrylis指出的那样,这样繁忙的循环非常低效。您需要做的是替换繁忙的循环:
一个hacky解决方案是将Thread.sleep()
调用放入循环(而不是println
调用)。
更好的解决方案是使用Object.wait()
和Object.notify()
。每次检查后,主线程在互斥对象上调用wait()
,并且每次进行更新时,正在进行更新的线程都会在同一个互斥锁上调用notify()
,这可能会导致&#34;韩元&#34;位置。
第二个解决方案还处理同步问题。只有在持有互斥锁时才能执行wait()
和notify()
方法;即在synchronized
块或方法中。
以下是一些代码片段,用于说明如何实现wait / notify。
public static final Object mutex = new Object();
public static boolean finished = false;
// One thread
synchronized (mutex) {
while (!finished) {
mutex.wait();
}
}
// Another thread
synchronized (mutex) {
finished = true;
mutex.notify();
}
显然,使用静力学只是为了说明目的。
答案 1 :(得分:0)
现在它运作的事实是一个意外。如果要强制计算机在每次循环中重新检查它,则需要声明变量volatile
;否则,它只能读取一次该值,而不会再次查看它。
此外,像这样的忙等待循环是非常低效的。相反,如果你想在win上退出,那么首先设置该标志的代码直接调用关闭代码。
答案 2 :(得分:0)
你有一个不断检查的忙等待循环。
为了缓解你可能会这样做:
Thread,sleep(100L);
而不是System.out.prinntln。
这不是一个干净的解决方案。
顺便说一下: 相反,如果
hasWon = hasWon && (board[i][z].getStatus() == winCond);
这有点快了
if (board[i][z].getStatus() != winCond) {
return false;
}
最好还是保留winConds的计数器。
因此,最好的解决方案是删除循环并更改网格,增加/减少计数器,以及在那里赢得退出