像这样,我有两个线程。SleepRunner线程在列表中添加一些随机数,然后将标志更改为true并Hibernate。主线程等待SleepRunner线程,直到SleepRunner对象中的标志从false变为true,然后主线程将中断SleepRunner线程,程序将结束。
但问题是,当主线程中的当循环没有正文代码时,变量“运行者”在循环内没有更新,换句话说,当睡眠运行者线程将标志从假改为真后,程序并没有结束。所以我在想法上尝试使用调试工具,但程序顺利结束。如果我在主线程中的当循环正文中写一些代码,比如System.out.println()或Thread.sleep(1),程序也成功结束了。太不可思议了!有人知道为什么会这样吗?谢谢。
public class Test1 {
public static void main(String[] args) {
SleepRunner runner = new SleepRunner();
Thread thread = new Thread(runner);
thread.start();
while(!(runner.isFlag())){
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
System.out.println("END");
thread.interrupt();
}
}
public class SleepRunner implements Runnable {
private boolean flag = false;
public boolean isFlag() {
return flag;
}
@Override
public void run() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
try {
Thread.sleep((long) (Math.random() * 200));
}
catch (InterruptedException e) {
System.out.println("Interrupted");
}
int num = (int) (Math.random() * 100);
System.out.println(Thread.currentThread().getName() + " " + num);
list.add(num);
}
flag = true;
System.out.println("30 Seconds");
try {
Thread.sleep(30000);
}
catch (InterruptedException e) {
System.out.println("Interrupted in 30 seconds");
}
System.out.println("sleep runner thread end");
}
}
你违反了java内存模型。
以下是JMM的工作原理*:
每当读取或更新任何字段(来自任何对象)时,每个线程都会抛出一枚硬币。正面,它会复制并据此更新/读取。反面,它不会。你的工作是确保你的代码正确运行,不管硬币是如何着陆的,你不能在单元测试中强制使用coinflip。硬币不需要“公平”。硬币的行为取决于你的音乐播放器中播放的音乐、幼儿的突发奇想和月亮的相位。(换句话说,任何更新/读取都可以对本地缓存副本进行,也可以不进行,直到java实现)。
你可以有把握地得出结论,正确操作的唯一方法是确保线不会翻转硬币。
实现这一目标的方法是建立所谓的“先到先得”关系。建立它们主要通过使用同步原语或调用使用同步原语的方法来完成。例如,如果我这样做:
线程X:
synchronized(x) {
x.foo();
System.out.println(shared.y);
shared.y = 10;
}
线程Y:
synchronized(x) {
x.foo();
System.out.println(shared.y);
shared.y = 20;
}
然后你就建立了一种关系:代码块a排在代码块B之前,反之亦然,但你至少已经确定它们必须按顺序运行。
因此,这将保证打印0 10
或0 20
。如果没有同步块,它也可以合法打印0
。这三个结果都是可以接受的结果(java lang规范说这没问题,任何你认为没有意义的bug都会被忽略为“按预期工作”)。
易失性
也可以使用,但易失性相当有限。
一般来说,由于无法对其进行充分测试,在java中只有3种方法可以正确执行线程:
psv main()
方法,框架需要编写,您只需要编写“处理程序”。您的处理程序中没有任何一个会接触任何共享数据。处理程序要么不共享数据,要么通过设计用于正确操作的总线共享数据,例如可串行事务隔离模式下的DB,或者rabbitmq或其他一些消息总线
*)完整的解释是关于一本书的价值。我只是给你们一个过于简单的亮点,因为这只是一个一般的答案。
问题内容: 为什么以下工作正常? 但是据说这是危险的/不正确的: 是否需要在循环外声明变量? 问题答案: 局部变量的范围应始终尽可能小。 在你的例子我相信是不会使用的外while循环,否则你就不会问这个问题,因为它声明的内部while循环不会是一个选项,因为它不会编译。 所以,既然是不使用外循环,在尽可能小的范围是内 while循环。 所以,答案是着重那绝对应该被while循环内声明。没有,没有,
我正在研究一个涉及for循环和if-else语句的java函数。我需要根据多次迭代中的条件更改标志变量的值。我声明了一个名为flag的变量,并希望根据每次迭代中的条件进行更改。我需要在每次迭代结束时打印flag变量的值。但是当我打印变量时,它显示了一个错误,变量没有初始化。如果我给它一个初始值,它会一直打印初始值,而不是在If-else语句中处理的值。我不能根据自己的要求初始化for循环中的fla
问题内容: java中是否允许这样做: 我的问题的关键词是。是否可以允许最终变量随循环的每次运行而变化?我想知道这是因为final说您不能更改变量的值(仅调用),但是我正在使用重新定义整个变量。 它们是两个完全不同的变量,只是具有相同的名称-循环的前一次运行中的变量已经朝着垃圾收集器的方向前进了吗? 问题答案: 是的,允许。该关键字意味着你不能改变的变量的值 的范围之内 。对于循环示例,您可以认为
如下所示,我要反转数组。但我的代码不管用。这是我的for循环。请看一下。这个for循环正确吗。代码如下。
循环变量内建函数从 FreeMarker 2.3.23 版本开始存在。 这些内建函数只能用于list 和 items 指令 的循环变量 (也可以用于已经废弃的 foreach 指令)。 下面是一些说明(loopVar?index 在可以列表的值中进行迭代,返回从0开始的索引): <#-- Note: x is a loop variable --> <#list ['a', 'b', 'c'] a
问题内容: 我相信在AS3中,您应该在循环外初始化所有变量,以提高性能。JavaScript也是如此吗?哪个更好/更快/最佳实践? 要么 问题答案: 有 绝对没有区别 意义还是性能,在JavaScript或ActionScript。 是解析器的指令,而 不是 运行时执行的命令。如果在函数体(*)中的任何位置一次或多次声明了特定的标识符,则该标识符在块中的所有使用将引用局部变量。声明是在循环内部,循