synchronized会以两种形式出现在代码中
1.synchronized(对象){}代码块形式
这种形式下,锁是加在括号内的对象上,所以你只需要看括号里面的对象指向的堆内存地址,如果内存地址相同,就会互斥,如果内存地址不同,就可以并发调用。
简单地用代码表示一下:
class Xxx{
static String demo = " ";
synchronized(demo){
}
}
对于以上代码,所有xxx类的对象访问的demo都是同一个内存地址:
比如:
Xxx x1 = new Xxx();
x1.demo;
Xxx x2 = new Xxx();
x2.demo;
x1和x2调用的demo其实是同一个,所以当x1调用该代码块时,x2再调用会发现demo上有锁,只能等待x1调用完毕再调用。
class Xxx{
String demo = " ";
synchronized(demo){
}
}
相反,如果demo没有static修饰,synchronized锁只会对同一个对象起作用,不同对象可以并发访问。
Xxx x1 = new Xxx();
x1.demo;
Xxx x2 = new Xxx();
x2.demo;
在这几行代码中,x1和x2所调用的demo是分别保存在两个内存地址中,当x1调用synchronized代码块时,x2再调用,会发现,自己的demo上没有锁,所以两个对象可以并发调用。还有一种特殊情况,synchronized(xxx.class){}这种情况也是对这个类的所有对象起作用的。
2.synchronized 方法名()方法形式
其实修饰方法和代码块形式也是差不多的,如果方法有static修饰,就对该类的所有对象起作用,相反,如果是个动态方法,则只会对同一对象起作用,不同对象可以并发执行。
下面简单叙述一下原理,当有线程执行synchronized代码块时,锁的标志是加在括号内的对象上的。当有线程再调用它时,会检查括号内对象锁的状态,所以当两次调用括号内对象指向不同内存时,是不影响并发执行的。
强调一点,锁加在对象上,只是限制synchronized代码块的调用,不会影响代码块中任何一个变量,对象,以及括号内对象的调用,以及读写操作。