先看一个简单示例,下面这段代码能够正常通过编译。
publicclassSyncTest {
publicSyncTest syncVar ;
publicstaticSyncTestsyncStaticVar;
publicstaticsynchronizedvoidtestStaticSync() {
}
publicsynchronizedvoidtestNonStaticSync() {
}
publicvoidtestSyncThis() {synchronized(this) {try{System.out.println( "test sync this start" ); Thread.sleep(5000); System.out.println( "test sync this end" ); }catch(InterruptedException e) {e.printStackTrace(); } } }
publicvoidtestSyncVar() {synchronized( syncVar ) {try{System.out.println( "test sync var start" ); Thread.sleep(3000); System.out.println( "test sync var end" ); }catch(InterruptedException e) {
} } }
publicvoidtestStaticSyncVar() {synchronized(syncStaticVar) {
} }
publicstaticvoidmain(String[] args) {finalSyncTest testSync =newSyncTest(); testSync. syncVar =newSyncTest(); testSync. syncVar = testSync; Thread threadOne =newThread(newRunnable() {@Overridepublicvoidrun() {testSync.testSyncThis(); } }); Thread threadTwo =newThread(newRunnable() {@Overridepublicvoidrun() {testSync.testSyncVar(); } }); threadOne.start(); threadTwo.start(); } }
从上面的代码来看,synchronized使用的场景很广,既能够锁住类方法(static),又能够锁住对象方法(非static)。既能够对某个属性加锁,又能够对this加锁。那么,sychronized到底锁住了什么?另外,synchronized也是可重入的,那么,它与单独的ReentrantLock的区别是什么?
sychronized在使用的时候也是区分目标对象的,在这一点上其实非常像前面提到过的ReentrantLock的使用。上面的代码中,如果把 testSync. syncVar = testSync;这句话注释掉,那么最后运行所产生的结果就会不一样。如果要和ReentrantLock做对比的话,可以把synchronized所针对的目标对象理解成一个锁,针对的目标对象不一样,那么就是不同的锁。
sychronized的实现原理需要深入到jvm中才能找到答案。。可以参考《深入理解Java虚拟机》
在这里主要讨论一个使用上的问题,当我们使用sychronized锁住某个对象时,我们锁住的是这个引用本身,还是内存(堆)中的这个对象本身。对这个问题的一个延伸是,当我们在sychronized作用区域内,为这个引用附一个新值的时候,sychronized是否还有效?
先给出结论,sychronized锁住的是内存(堆)中的对象,当引用被附上新值的时候,则相当于旧对象的锁被释放。这里不做理论讨论,只是用程序进行验证。
用三个例子进行说明,
示例1、publicclassTestSyncAndModifyimplementsRunnable {
privateA syncA ;
@Overridepublicvoidrun() {synchronized( syncA ) {System.out.println(Thread.currentThread().getName()); syncA=newA();try{Thread.sleep(3000); }catch(InterruptedException e) {e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } }
staticclassA {};
publicstaticvoidmain(String[] args) {TestSyncAndModify sync =newTestSyncAndModify(); A testA =newA(); sync. syncA = testA; Thread one =newThread(sync); Thread two =newThread(sync); one.start();try{Thread.sleep(1000); }catch(InterruptedException e) {e.printStackTrace(); } two.start(); } }
在sychronized作用域内对syncA做了修改,使它指向了一个新的对象,所以当这句话执行完之后,第二个线程就可以运行,因此输出的结果如下
Thread-0 Thread-1 Thread-0 Thread-1
示例2、就是最上面的那段代码SyncTest。在main函数内,有这样一句赋值 testSync. syncVar = testSync;使得syncVar成员变量,指向了和this相同的区域。因此,在sychronized(this)和synchronized(syncVar)就形成了竞争,使得后者被阻塞,因此输出结果如下 test sync this start test sync this end test sync var start test sync var end
示例3publicclassThreadUseBaseextendsThread {
privateBase baseObject ;
publicThreadUseBase(Base boj) {baseObject = boj; }
publicvoidtestSyncBase() {synchronized( baseObject ) {System.out.println( "enter thread use base" );try{Thread.sleep(2000); }catch(InterruptedException e) {e.printStackTrace(); } System.out.println( "leave thread use base" ); } }
@Overridepublicvoidrun() {testSyncBase(); }
staticclassThreadUseChildextendsThread {privateSyncObject childObj ;
publicThreadUseChild(SyncObject sobj) {childObj = sobj; }
publicvoidtestSyncChild() {synchronized( childObj ) {System.out.println( "enter thread use child" );try{Thread.sleep(2000); }catch(InterruptedException e) {e.printStackTrace(); } System.out.println( "leave thread use child" ); } }
@Overridepublicvoidrun() {testSyncChild(); } }
staticclassBase {
}
staticclassSyncObjectextendsBase {
}
publicstaticvoidmain(String[] args) {SyncObject childObj =newSyncObject(); Base baseObj = childObj; //Base baseObj =newBase(); ThreadUseBase threadBase =newThreadUseBase(baseObj); ThreadUseChild threadChild =newThreadUseChild(childObj); threadBase.start(); threadChild.start(); }
}
虽然是两个线程中,sychronized锁住的是不同的引用,一个是Base一个是SyncObject,但由于存在继承关系,在main函数中,我们让Base对象也指向了SyncObject内存区域。这样,就形成了两个不同线程之间的竞争,因此后者被阻塞,输出结果如下 enter thread use base leave thread use base enter thread use child leave thread use child
参考论文如下 JVM的锁结构设计原理 --- /legacy/event/jvm01/full_papers/dice/dice.pdf