java两把锁才能安全_Java多线程5:Synchronized锁机制

通过这两段描述,我们应该能很清楚的看出Synchronized的实现原理,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

具体的解释:

1、当thread01执行getNumByUserName方法碰到synchronized关键字时,执行monitorenter指令,thread01去获取与threadSynch对象关联的monitor(监视器)的entry count,此时与threadSynch对象关联的monitor(监视器)的entry count是0,所以thread01进入该监视器并将其entry count设置为1,thread01此时是与threadSynch对象关联的monitor(监视器)的所有者。

2、thread01执行getNumByUserName方法sleep的时候,thread02进来执行该方法,但如上所述,thread01此时是与threadSynch对象关联的monitor(监视器)的所有者,thread02进入阻塞状态。

3、thread01执行getNumByUserName方法结束,执行monitorexit指令,thread01将与threadSynch对象关联的monitor(监视器)的entry count减1,此时entry count为0,thread01退出monitor,不在是其所有者。

4、处于阻塞状态的thread02重新进入与threadSynch对象关联的monitor(监视器),获取所有权,此时与threadSynch对象关联的monitor(监视器)的entry count是0,接下来的步骤与1中相同。

3.2 synchronized修饰普通方法

public classThreadSynch {private intnum;public synchronized voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}

反编译结果:

7566e51c83ae4dc83384df8f18f473d0.png

从反编译结果来看,方法的同步并没有通过monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。

3.3 synchronized修饰静态方法

public classThreadSynch {private static intnum;public static synchronized voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}

反编译结果:

bb3c1f8905a821df9119f8abbebf5ca7.png

可以看到,静态方法的同步和普通方法的同步其实现方式都是一样的。

通过实例验证:

① 多线程访问同一对象-----同一方法-----不加锁

上述的多线程安全问题实例已经演示过了。

② 多线程访问同一对象-----同一方法-----加锁

上述讲解synchronized原理已经演示过了。

③ 多线程访问同一对象-----不同方法-----两个方法都不加锁

为了方便,两个方法操作的是不同的属性

线程:thread01、thread02

同一对象:ThreadSynch

两个方法:getNumByUserName、getIDByUserName

线程访问的对象:

public classThreadSynch {private intnum;private intid;public voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}public voidgetIDByUserName(String userName){if("zs".equals(userName)){try{

id= 1;

System.out.println("zs setID 1");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

id= 2;

System.out.println("ls setID 2");

}

System.out.println(" " + userName + " id ======" +id);

}

}

thread01:

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("zs");

}

}

thread02:

public class Thread02 extendsThread{privateThreadSynch threadSynch;publicThread02(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getIDByUserName("zs");

}

}

测试:

public classTest {public static voidmain(String[] args) {

ThreadSynch threadSynch= newThreadSynch();//两个线程访问同一个对象

Thread thread01 = newThread01(threadSynch);

Thread thread02= newThread02(threadSynch);

thread01.start();

thread02.start();

}

}

结果:

zs setNum 100zs setID1zs num======100zs id======1

说明:两个线程访问同一个对象的不同方法,两个方法都没有加锁,那么两个线程就不存在一个等待另一个执行完再执行的问题,即各执行各的,也不存在线程安全问题。

④ 多线程访问同一对象-----不同方法-----两个方法都加锁

线程:thread01、thread02

同一对象:ThreadSynch

加锁的两个方法:getNumByUserName、getIDByUserName

public classThreadSynch {private intnum;private intid;public voidgetNumByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}public voidgetIDByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

id= 1;

System.out.println("zs setID 1");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

id= 2;

System.out.println("ls setID 2");

}

System.out.println(" " + userName + " id ======" +id);

}

}

}

结果:

zs setNum 100zs num======100zs setID1zs id======1

说明:两个线程访问同一对象的不同方法,这两个方法都加了锁,那么thread01执行getNumByUserName方法的时候,根据synchronized的原理,thread01是与threadSynch对象关联的monitor(监视器)的所有者,该monitor的entry count是1,所以虽然thread02执行的是另一个方法getIDByUserName,但还是处于阻塞状态,必须等待thread01执行完后,不再是monitor的所有者,thread02才能执行。

⑤ 多线程访问同一对象-----不同方法-----一个方法加锁,一个方法不加锁

线程:thread01、thread02

同一对象:ThreadSynch

加锁的方法:getNumByUserName

不加锁的方法:getIDByUserName

public classThreadSynch {private intnum;private intid;public voidgetNumByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}public voidgetIDByUserName(String userName){if("zs".equals(userName)){try{

id= 1;

System.out.println("zs setID 1");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

id= 2;

System.out.println("ls setID 2");

}

System.out.println(" " + userName + " id ======" +id);

}

}

结果:

zs setNum 100zs setID1zs id======1zs num======100

说明:两个线程访问同一对象的不同方法,getNumByUserName方法加了锁,getIDByUserName方法没加锁。那么thread01执行getNumByUserName方法的时候,根据synchronized的原理,先判断与threadSynch对象关联的monitor(监视器)是否被哪个线程所有,没有,thread01就是与threadSynch对象关联的monitor的所有者,该monitor的entry count是1。thread02执行getIDByUserName方法,因为该方法没有加锁,所以无需判断与threadSynch对象关联的monitor是否被哪个线程所有(此时该monitor被thread01所有,但与thread02无关),即thread01和thread02各执行各的,无需等待哪一方执行结束在执行。

⑥ 多线程访问不同对象-----同一方法-----不加锁

线程:thread01、thread02

不同对象:threadSynch01,threadSynch02

不加锁的方法:getNumByUserName

线程访问的对象:

public classThreadSynch {private intnum;public voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}

thread01:

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("zs");

}

}

thread02:

public class Thread02 extendsThread{privateThreadSynch threadSynch;publicThread02(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("ls");

}

}

测试:

public classTest {public static voidmain(String[] args) {

ThreadSynch threadSynch1= newThreadSynch();

ThreadSynch threadSynch2= newThreadSynch();//两个线程访问两个不同的对象

Thread thread01 = newThread01(threadSynch1);

Thread thread02= newThread02(threadSynch2);

thread01.start();

thread02.start();

}

}

结果:

zs setNum 100ls setNum200ls num======200zs num======100

说明:两个线程访问不同对象(同一个类)的同一方法,getNumByUserName方法没有加锁。方法没加锁,说明不需要判断与threadSynch对象关联的monitor(监视器)被谁所有,两个线程各执行各的,所操作的num属性也是自己对象中的。

⑦ 多线程访问不同对象-----同一方法-----加锁

线程:thread01、thread02

不同对象:threadSynch01,threadSynch02

加锁的方法:getNumByUserName

public classThreadSynch {private intnum;public voidgetNumByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}

}

结果:

zs setNum 100ls setNum200ls num======200zs num======100

说明:两个线程访问不同对象的同一方法,getNumByUserName方法加了锁。那么thread01执行getNumByUserName方法的时候,根据synchronized的原理,先判断与threadSynch1对象关联的monitor(监视器)是否被哪个线程所有,没有,thread01就是与threadSynch1对象关联的monitor的所有者,该monitor的entry count是1。与此同时,thread02执行getNumByUserName方法,根据synchronized的原理,先判断与threadSynch2对象关联的monitor(监视器)是否被哪个线程所有,没有,thread02就是与threadSynch2对象关联的monitor的所有者,该monitor的entry count是1。如上,因为thread01和thread02访问的是两个不同的对象,各自获取与各自对象相关的monitor的所有权,所以两个线程各执行各的,不存在一个线程等待另一个线程的问题。

⑧ 多线程访问不同对象-----不同方法-----都不加锁

线程:thread01、thread02

不同对象:threadSynch01,threadSynch02

都不加锁的方法:getNumByUserName,getIDByUserName

线程访问的对象:

public classThreadSynch {private intnum;private intid;public voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}public voidgetIDByUserName(String userName){if("zs".equals(userName)){try{

id= 1;

System.out.println("zs setID 1");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

id= 2;

System.out.println("ls setID 2");

}

System.out.println(" " + userName + " id ======" +id);

}

}

thread01:

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("zs");

}

}

thread02:

public class Thread02 extendsThread{privateThreadSynch threadSynch;publicThread02(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getIDByUserName("ls");

}

}

测试:

zs setNum 100ls setID2ls id======2zs num======100

说明:两个线程访问不同对象的不同方法,getNumByUserName方法和getIDByUserName方法都没加锁。那么thread01执行getNumByUserName方法的时候,无需判断与threadSynch1对象关联的monitor(监视器)是否被哪个线程所有,类似的,thread02执行getIDByUserName方法,也无需判断与threadSynch2对象关联的monitor(监视器)是否被哪个线程所有,所以两个线程各执行各的。

⑨ 多线程访问不同对象-----不同方法-----都加锁

线程:thread01、thread02

不同对象:threadSynch01,threadSynch02

都加锁的方法:getNumByUserName,getIDByUserName

public classThreadSynch {private intnum;private intid;public voidgetNumByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}public voidgetIDByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

id= 1;

System.out.println("zs setID 1");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

id= 2;

System.out.println("ls setID 2");

}

System.out.println(" " + userName + " id ======" +id);

}

}

}

测试:

zs setNum 100ls setID2ls id======2zs num======100

说明:两个线程访问不同对象的不同方法,getNumByUserName方法和getIDByUserName方法都加锁。那么thread01执行getNumByUserName方法的时候,先判断与threadSynch1对象关联的monitor(监视器)是否被哪个线程所有,没有,thread01是与threadSynch1对象关联的monitor的所有者,该monitor的entry count是1,类似的,thread02执行getIDByUserName方法,先判断与threadSynch2对象关联的monitor(监视器)是否被哪个线程所有,没有,thread02是与threadSynch2对象关联的monitor的所有者,该monitor的entry count是1,因为thread01和thread02获取的是各自对象关联的monitor的所有权,所以两个线程各执行各的。

⑩ 多线程访问不同对象-----不同方法-----一个方法加锁,一个方法不加锁

线程:thread01、thread02

不同对象:threadSynch1,threadSynch2

加锁的方法:getNumByUserName

不加锁的方法:getIDByUserName

public classThreadSynch {private intnum;private intid;public voidgetNumByUserName(String userName){synchronized(this){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}public voidgetIDByUserName(String userName){if("zs".equals(userName)){try{

id= 1;

System.out.println("zs setID 1");

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

id= 2;

System.out.println("ls setID 2");

}

System.out.println(" " + userName + " id ======" +id);

}

}

测试:

zs setNum 100ls setID2ls id======2zs num======100

说明:两个线程访问不同对象的不同方法,getNumByUserName方法加锁,getIDByUserName方法没加锁。那么thread01执行getNumByUserName方法的时候,先判断与threadSynch1对象关联的monitor(监视器)是否被哪个线程所有,没有,thread01是与threadSynch1对象关联的monitor的所有者,该monitor的entry count是1,thread02执行getIDByUserName方法,该方法没加锁,无需判断与threadSynch2对象关联的monitor(监视器)是否被哪个线程所有,所以两个线程各执行各的。

四、Synchronized的可重入性

synchronized拥有锁重入的功能,所谓锁重入的意思就是:当一个线程得到一个对象锁后,再次请求该对象锁时可以再次得到该对象锁。这也证明在一个Synchronized方法/块的内部调用本类的其他Synchronized方法/块的时候,是永远可以得到锁的,因为锁都是同一个对象锁。

举例:

public classThreadSynch {public synchronized voidprint1(){

System.out.println("print1========");

print2();

}public synchronized voidprint2(){

System.out.println("print2========");

print3();

}public synchronized voidprint3(){

System.out.println("print3========");

}

}

thread01中调用上述对象的print1()方法

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.print1();

}

}

测试:

public classTest {public static voidmain(String[] args) {

ThreadSynch threadSynch= newThreadSynch();

Thread thread01= newThread01(threadSynch);

thread01.start();

}

}

结果:

print1========print2========print3========

说明:thread01执行同步方法print1的时候,根据synchronized的原理,thread01先判断与threadSynch对象关联的monitor(监视器)是否被哪个线程所有,没有,thread01就是与threadSynch对象关联的monitor(监视器)的所有者,该monitor的entry count是1。

同步方法print1中调用同步方法print2,根据synchronized的原理,thread01先判断与threadSynch对象关联的monitor(监视器)是否被哪个线程所有,被自己占有,那就可以重新进入该monitor,其entry count加一变成2。

同步方法print2中调用同步方法print3,根据synchronized的原理,thread01先判断与threadSynch对象关联的monitor(监视器)是否被哪个线程所有,被自己占有,那就可以重新进入该monitor,其entry count加一变成3。

同步方法print3执行结束,与threadSynch对象关联的monitor(监视器)的entry count减一变成2。

同步方法print2执行结束,与threadSynch对象关联的monitor(监视器)的entry count减一变成1。

同步方法print1执行结束,与threadSynch对象关联的monitor(监视器)的entry count减一变成0。thread01不在是与threadSynch对象关联的monitor(监视器)的所有者。

这种锁重入的机制,也支持在父子类继承的环境中。子类同步方法中可以通过“锁重入”调用父类的同步方法。

五、异常自动释放锁

当一个线程执行的代码发生异常时,其所占有的锁会自动释放。

举例:两个线程访问同一对象的加锁方法

public classThreadSynch {public synchronized voidexceptionTest(){int num = 10000;

System.out.println("currentThread ===" +Thread.currentThread().getName());try{

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}while(true){int n = 2 /num;

num--;

}

}

}

thread01:

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.exceptionTest();

}

}

thread02:

public class Thread02 extendsThread{privateThreadSynch threadSynch;publicThread02(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.exceptionTest();

}

}

测试:

public classTest {public static voidmain(String[] args) {

ThreadSynch threadSynch= newThreadSynch();

Thread thread01= newThread01(threadSynch);

Thread thread02= newThread02(threadSynch);

thread01.start();

thread02.start();

}

}

结果:

currentThread ===Thread-0Exception in thread"Thread-0" java.lang.ArithmeticException: /by zero

at com.dajia.test.ThreadSynch.exceptionTest(ThreadSynch.java:23)

at com.dajia.test.Thread01.run(Thread01.java:26)

currentThread===Thread-1Exception in thread"Thread-1" java.lang.ArithmeticException: /by zero

at com.dajia.test.ThreadSynch.exceptionTest(ThreadSynch.java:23)

at com.dajia.test.Thread02.run(Thread02.java:25)

说明:thread01进来后,打印出“currentThread ===Thread-0”后,sleep了两秒,因为sleep方法并不释放锁,所以此时thread02还处于阻塞状态,直到thread01继续执行,抛异常后释放锁,thread02才开始执行。

六、Synchronized用法总结

synchronized的作用主要有三个:

1、确保线程互斥的访问同步代码

2、保证共享变量的修改能够同步可见

3、有效解决重排序问题

从语法上讲,Synchronized总共有三种用法:

1、修饰普通方法

2、修饰静态方法

3、修饰代码块

synchronized修饰代码块上面列举的实例全部都是,下面说一下另外两种的用法:

1 修饰普通方法

线程:thread01、thread02

不同对象:threadSynch01,threadSynch02

加锁的方法:getNumByUserName

public classThreadSynch {private intnum;public synchronized voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}

thread01:

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("zs");

}

}

thread02:

public class Thread02 extendsThread{privateThreadSynch threadSynch;publicThread02(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("ls");

}

}

测试:

public classTest {public static voidmain(String[] args) {

ThreadSynch threadSynch1= newThreadSynch();

ThreadSynch threadSynch2= newThreadSynch();//两个线程访问两个不同的对象

Thread thread01 = newThread01(threadSynch1);

Thread thread02= newThread02(threadSynch2);

thread01.start();

thread02.start();

}

}

结果:

zs setNum 100ls setNum200ls num======200zs num======100

说明:多线程访问不同对象加锁的方法时,因为各自获取与各自对象关联的那个monitor,所以各执行各的,不存在一个等待另一个的问题。

2 修饰静态方法

线程:thread01、thread02

不同对象:threadSynch01,threadSynch02

加锁的方法:getNumByUserName

线程访问的对象:

public classThreadSynch {private static intnum;public static synchronized voidgetNumByUserName(String userName){if("zs".equals(userName)){try{

num= 100;

System.out.println("zs setNum 100");

Thread.sleep(5000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}else if("ls".equals(userName)){

num= 200;

System.out.println("ls setNum 200");

}

System.out.println(" " + userName + " num ======" +num);

}

}

thread01:

public class Thread01 extendsThread{privateThreadSynch threadSynch;publicThread01(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("zs");

}

}

thread02:

public class Thread02 extendsThread{privateThreadSynch threadSynch;publicThread02(ThreadSynch threadSynch) {this.threadSynch =threadSynch;

}

@Overridepublic voidrun() {

threadSynch.getNumByUserName("ls");

}

}

测试:

public classTest {public static voidmain(String[] args) {

ThreadSynch threadSynch1= newThreadSynch();

ThreadSynch threadSynch2= newThreadSynch();//两个线程访问两个不同的对象

Thread thread01 = newThread01(threadSynch1);

Thread thread02= newThread02(threadSynch2);

thread01.start();

thread02.start();

}

}

结果:

zs setNum 100zs num======100ls setNum200ls num======200

说明:对静态方法的同步本质上是对类的同步(静态方法本质上是属于类的方法,而不是对象上的方法),虽然threadSynch1和threadSynch2是两个不同的对象,但都是ThreadSynch这个类的实例,thread01执行getNumByUserName方法的时候,会获取与ThreadSynch这个类关联的monitor的所有权,此时thread02执行getNumByUserName方法的时候,也会获取与ThreadSynch这个类关联的monitor的所有权,但该monitor已经被thread01所有,所以thread02只能进入阻塞状态,等待thread01执行完释放monitor的所有权后,才能执行getNumByUserName方法。

参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值