100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > synchronized锁住了什么

synchronized锁住了什么

时间:2019-06-21 03:32:06

相关推荐

synchronized锁住了什么

先看一个简单示例,下面这段代码能够正常通过编译。

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。