插入 System.out.println 调用会影响竞争条件:如何调试?
Inserting System.out.println calls affects race conditions: how to debug?
我不明白为什么添加println注释后下面代码中的竞争条件消失了。
这确实使调试变得困难。
那我们如何调试这些条件呢?
在下面的代码中,机器应该抛出异常,因为两个线程以不一致的方式修改了 class 的内容。
事实上检查代码 b 应该总是大于或等于 a(class 合同)。然而,由于两个线程之间的竞争条件,这个契约不满足。
没有注释,竞争条件发生,代码抛出异常,但是有 System.out.println 注释,我没有得到任何竞争条件。
Java 版本 1.8.0_112
package lectures;
import java.util.Random;
public class Concurrency1 {
int a,b;
void setEqual(int x){
// System.out.println("setEqual "+x);
a=x;
b=x;
}
void setRel(){
// System.out.println("setRel");
a++;
b+=a;
}
void checkContract() throws Exception{
if (b<a) throw new Exception("b<a!!, a="+a+" b="+b);
}
public static void main(String[] args) throws Exception{
Concurrency1 c1=new Concurrency1();
final int count=10000000;
Thread t1=new Thread(){
public void run(){
Random gen=new Random();
int c=0;
while(c++<count){
System.out.println("setEqual ");
c1.setEqual(gen.nextInt(10));
}
}};
Thread t2=new Thread(){
public void run(){
int c=0;
while(c++<count){
System.out.println("setGen ");
c1.setRel();
}
}};
t1.start();
t2.start();
int c=0;
while(t1.isAlive()||t2.isAlive()||c++<count){
c1.checkContract();
}
}
}
如果没有 println 消息,我会收到如下异常消息:
Exception in thread "main" java.lang.Exception: b<a!!, a=104 b=27966
at lectures.Concurrency1.checkContract(Concurrency1.java:20)
at lectures.Concurrency1.main(Concurrency1.java:48)
检查完成后更改值的位置...
这与 Loop doesn't see changed value without a print statement 不同,因为线程正在看到彼此的更改并因此生成异常
System.out::println
包含一个 synchronized
块,它导致 Threads
逐个顺序访问资源。
来自PrintStream.java
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
这可能充当过滤器。对方法 setRel
和 setEqual
的多线程调用首先由 System.out::println
组织,然后仅 一次 .[=18 执行剩余的语句=]
虽然不确定。
我不明白为什么添加println注释后下面代码中的竞争条件消失了。 这确实使调试变得困难。
那我们如何调试这些条件呢?
在下面的代码中,机器应该抛出异常,因为两个线程以不一致的方式修改了 class 的内容。
事实上检查代码 b 应该总是大于或等于 a(class 合同)。然而,由于两个线程之间的竞争条件,这个契约不满足。
没有注释,竞争条件发生,代码抛出异常,但是有 System.out.println 注释,我没有得到任何竞争条件。
Java 版本 1.8.0_112
package lectures;
import java.util.Random;
public class Concurrency1 {
int a,b;
void setEqual(int x){
// System.out.println("setEqual "+x);
a=x;
b=x;
}
void setRel(){
// System.out.println("setRel");
a++;
b+=a;
}
void checkContract() throws Exception{
if (b<a) throw new Exception("b<a!!, a="+a+" b="+b);
}
public static void main(String[] args) throws Exception{
Concurrency1 c1=new Concurrency1();
final int count=10000000;
Thread t1=new Thread(){
public void run(){
Random gen=new Random();
int c=0;
while(c++<count){
System.out.println("setEqual ");
c1.setEqual(gen.nextInt(10));
}
}};
Thread t2=new Thread(){
public void run(){
int c=0;
while(c++<count){
System.out.println("setGen ");
c1.setRel();
}
}};
t1.start();
t2.start();
int c=0;
while(t1.isAlive()||t2.isAlive()||c++<count){
c1.checkContract();
}
}
}
如果没有 println 消息,我会收到如下异常消息:
Exception in thread "main" java.lang.Exception: b<a!!, a=104 b=27966
at lectures.Concurrency1.checkContract(Concurrency1.java:20)
at lectures.Concurrency1.main(Concurrency1.java:48)
检查完成后更改值的位置... 这与 Loop doesn't see changed value without a print statement 不同,因为线程正在看到彼此的更改并因此生成异常
System.out::println
包含一个 synchronized
块,它导致 Threads
逐个顺序访问资源。
来自PrintStream.java
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
这可能充当过滤器。对方法 setRel
和 setEqual
的多线程调用首先由 System.out::println
组织,然后仅 一次 .[=18 执行剩余的语句=]
虽然不确定。