我们假设我有两个线程t1
和t2
正在尝试访问incX()
以下是我的以下代码:
class Test implements Runnable {
private int x = 0;
public void incX() {
synchronized(this) {
x = ++x;
}
System.out.println("x is: "+x+" "+Thread.currentThread().getName());
}
public void run() {
incX();
}
public static void main(String[] args) {
Thread t1 = new Thread(new Test());
t1.start();
Thread t2 = new Thread(new Test());
t2.start();
}
这是我的输出:
x is: 1 Thread-1
x is: 1 Thread-0
与incX()
方法一样,我已同步x = ++x
,因此对线程t1
所做的更改应该对线程t2
可见,对吧?所以我的输出应该是:
x is: 1 Thread-1
x is: 2 Thread-0
我知道++x
不是原子操作,但它是同步的,因此线程t2
无法获取锁。因此,线程不应interleave
,并且x
对t2
所做的更改应该对线程 x is: 2 Thread-0
可见,对吧?我误会了吗?
所以我的问题是为什么我没有得到输出:
{{1}}
答案 0 :(得分:9)
您正在使用Test
类的两个单独的实例,因此每个x
中的Test test1 = new Test();
Test test2 = new Test();
test1.incX();
test2.incX();
只会增加一次。它实际上与此相同:
Test
由于x
的每个实例都有自己的1
,因此您也会看到class Test {
private int x = 0;
public void incX() {
synchronized(this) {
x = ++x; // See "Side Note" below
}
System.out.println("x is: "+x+" "+Thread.currentThread().getName());
}
}
public class Main {
public static void main(String[] args) {
Test test = new Test(); // One instance
Thread t1 = new Thread(() -> {
test.incX(); // Used by this thread
});
Thread t2 = new Thread(() -> {
test.incX(); // And also by this one
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
}
catch (Exception e) {
}
System.out.println("Done");
}
}
两次该代码。
要测试对相同实例的同步访问,您需要使用单个实例。例如:
x
将输出
x is: 1 Thread-0 x is: 2 Thread-1 Done
或类似(当然,这取决于在什么时间安排的线程)。
有时,它甚至看起来像这样:
x is: 2 Thread-0 x is: 2 Thread-1 Done
这是因为System.out.println
语句中对synchronized
的访问权限在<{em>} x
块之外,因此有时(并非总是)synchronized
将会在println
块结束后synchronized(this) {
x = ++x;
}
// ***The other thread can jump in here and increment x
System.out.println("x is: "+x+" "+Thread.currentThread().getName());
:
t1
更详细:
t2
进入已同步的块t1
尝试输入已同步的块,但必须等待,因为t1
有锁x
增加t1
,使其成为1 t2
退出已同步的块x
跳入并增加t2
,使其成为2 t1
退出已同步的块x
输出{em}当前值t2
(2)x
输出{em}当前值x
(2)请注意,步骤2和步骤3可以是任何顺序,步骤6-8也可以是任何顺序。
为了在递增后可靠地报告同步块内的println
,我们想要:
将public void incX() {
synchronized(this) {
x = ++x; // See "Side Note" below
System.out.println("x is: "+x+" "+Thread.currentThread().getName());
}
}
移动到同步块
public void incX() {
int y; // Local variable
synchronized(this) {
y = ++x; // No longer and odd thing to do
}
System.out.println("x is: "+y+" "+Thread.currentThread().getName());
}
或
将增量结果保存在局部变量
中++x
除非你有一个非常好的理由在输出期间保持同步锁定,否则请使用#2。
旁注:正如我在评论中提到的,x
已经将其值写回x =
,这就是增量运算符的作用。
x = ++x;
部分
++x;
......是不必要的。使用增量运算符:
x += 1;
......或不要:
public class prac {
public static void main (String args []){
String a = "wtf";
String b = "wtf";
System.out.println("WHY" + a==b);
}
}