此代码没有内部类:
class Threads1 implements Runnable {
int x = 0;
public void run(){
int current = 0;
for(int i = 0; i<4; i++){
current = x;
System.out.println(current + ", ");
x = current + 2;
}
}
}
public class b{
public static void main(String[] args) {
Runnable r1 = new Threads1();
new Thread(r1).start();
new Thread(r1).start();
}
}
输出:
0, 2, 0, 4, 6, 2, 4, 6
此代码使用名为“Runner”的内部类:
public class Threads1 {
int x = 0;
public class Runner implements Runnable {
public void run(){
int current = 0;
for(int i = 0; i<4;i++){
current = x;
System.out.println(current + ", ");
x = current + 2;
}
}
}
public static void main(String[] args) {
new Threads1().go();
}
public void go(){
Runnable r1 = new Runner();
new Thread(r1).start();
new Thread(r1).start();
}
}
输出:(0,2,4,4,6,8,10,6,)或(0,2,4,6,8,10,12,14)
我了解到,当创建两个线程时,它们在自己的堆栈上工作,这意味着它们彼此不共享,即输出(0,2,0,4,6,2,4,6)可能来自( T1,T1,T2,T1,T1,T2,T2,T2)其中T1和T2是线程1和线程2.
但是,当我在内部类中使用run()
时,两个线程彼此共享Current
变量。例如,输出(0,2,4,4,6,8,10,6)可能来自(T1,T1,T1,T2,T2,T2,T2,T1)。正如您所看到的,输出中有两个4,这意味着thread1将其值传递给thread2。为什么会这样?
答案 0 :(得分:3)
您的检查探索未定义的行为。以线程不安全的方式访问同一字段的线程可能会也可能不会看到相同的值。
在第一个示例中,字段x
正在被缓存,就像它是一个局部变量一样。没有保证在不同版本的JVM上或在编译代码之后会发生这种行为。
在第二种情况下,您有一个额外的间接级别,这意味着JIT不太可能优化x
对局部变量的访问。然而,再次微妙的变化可能会看到不同的行为。
答案 1 :(得分:1)
they work on there own stacks which means they share nothing with eachother
那是错的。线程确实有不同的堆栈,但它们共享堆(即所有对象实例及其成员变量所在的内存,只有函数变量位于堆栈中)
并且int x
只在堆上存在一次,因为您只创建了一个Threads1
对象,并且Runnable
都共享它
您应该将int x
移到Runner
类,并为每个帖子创建一个新的Runner
对象。
when i used run() in inner class both thread shares "Current" variable with eachother
也是错误的,他们实际上共享int x
变量,如前所述。 current
对每个帖子都是唯一的
答案 2 :(得分:0)
因为x是共享的,所以它在包含类中。
答案 3 :(得分:0)
在第一种情况下,x
是Threads1类的成员,但是Threads1
由b
clas单独实例化,因此每个线程都获得它自己的x
。在第二种情况下,x
是外部Threads1的成员,因此只创建了x
的一个实例。