private Object x = new Object();
public void doA() {
synchronized(x){
x = new Object();
//do something
}
}
public void doB() {
synchronized(x) {
//do something
}
}
让doA()
和doB()
同时被调用,但doA()
首先进行。因此B将被阻止,直到doA()
完成
即使doA()
在x = new x
调用中修改了x,这是否成立?还是在x = new x
doA()
中的这一行doB()
之后,由于x
发生了变化,将不再被阻止?
答案 0 :(得分:3)
究竟发生了什么,实际上取决于doA()
的运行速度:
如果doA()
在x
到达其同步块之前更改了doB()
的值,则doB()
将锁定{ {1}}已创建。
如果doA()
快速并且doB()
部分得到评估,而synchronized(x)
可以更改doA()
的值,那么x
将不得不等到{ {1}}的{{1}}块结束。
每当Java使用任一方法访问doB()
代码时,它都会评估变量doA()
,该变量为Java提供一个对象。因此,Java然后尝试锁定该对象,并保持锁定状态。或者,如果该对象上已经有一个锁,它将等待该锁消失。 (每当Java到达synchronized
代码时,它都会获取变量的值,而忽略变量本身的遗忘,因此以后您可以随意更改变量,但是锁定和锁定检查仍会在变量的先前值上进行。 )
答案 1 :(得分:2)
我的好奇心得到了我的最好的帮助,我编写了此测试来验证会发生什么。该锁仍保留在原始参考上,并且不会更改。
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class Test {
private static Object x = new Object();
public static void main(String[] args) throws Exception {
Test a = new Test();
Test b = new Test();
Thread t = new Thread(a.new MyRunnable());
t.start();
Thread.sleep(100);
b.doB();
}
public void doB() {
System.out.println("here b");
synchronized (x) {
System.out.println("here sync b");
}
System.out.println("here done sync b");
}
public class MyRunnable implements Runnable {
public MyRunnable() {
}
public void run() {
System.out.println("here a");
synchronized (x) {
System.out.println("here sync a");
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
x = new Object();
System.out.println("here new object a");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("here after sleep a");
}
System.out.println("here done sync a");
}
}
}
输出如下。显然,即使重新分配后,该锁仍然保留在原始参考上。
here a
here sync a
here b
here new object a
here after sleep a
here done sync a
here sync b
here done sync b
答案 2 :(得分:1)
我认为doA()方法仍将锁定旧的“ x”。除非线程保持完成对同步块的处理,否则不会通知其他等待锁定“ x”的线程。 同步块完成后,线程将争夺对x新实例的锁定。