java synchronized修饰static方法与非static方法的区别

如果使用synchronized修饰static方法,会发生什么?

 

一、问题的解答

先回顾一下上篇文章:

http://www.xie4ever.com/2017/10/26/java-%E6%9B%B4%E6%AD%A3%E5%AF%B9synchronized%E7%9A%84%E4%B8%80%E4%B8%AA%E9%94%99%E8%AF%AF%E8%AE%A4%E8%AF%86/

在上篇文章中,我们得到了一个结论:

多个线程访问同一个类的synchronized方法时, 都是串行执行的(就算有多个cpu也不例外)!synchronized方法使用了类的内置锁, 锁住的是方法所属对象本身

现在我改造一下上篇文章的第一个例子,使用synchronized修饰static方法,看看会发生什么。

Test.java

只改造了一下method1,改成了static方法。运行结果为:

为什么可以实现并发了?难道static导致同步方法失效了吗?我们把method2也改成static方法,看看会发生什么。

运行结果为:

两个方法又不能并发了…

现在我们现在可以确定,synchronized修饰的static方法彼此之间能够实现同步,但是static方法和非static方法之间不能实现同步。如果仍然使用“test对象的对象锁”来解释这种现象,肯定是解释不通的。

个人认为:synchronized修饰的static方法和非static方法分别使用了两种不同的锁,所以才没有实现同步。

这里借用别人总结的结论:

当synchronized修饰一个static方法时,获取的是类锁(即Class本身,注意:不是实例)

当synchronized修饰一个非static方法时,获取的是对象锁(即类的实例对象)

如果Thread1要访问static synchronized method1,就要获取Test类的类锁(method1所属的类),一但Thread1获得了类锁,在主动释放之前,(竞争类锁的)别的线程都需要等待。

假设现在Thread2想要访问static synchronized method2,就要先获得Test类的的类锁。因为当前类锁被Thread1占用了,所以Thread2只能进入Test类的锁池内,等待锁的释放。

另一种情况:假设现在Thread2想要访问synchronized method2,就要先获得test对象的对象锁。因为当前test的对象锁没有被任何线程占用,所以Thread2获取对象锁后,马上就可以执行synchronized method2,体现为Thread1、Thread2并发。

二、如何使static方法和非static方法同步?

既然static方法和非static方法竞争的是不同的锁,那么在同一个类中,如何使这两种方法同步?

用synchronized应该是做不到的,我们可以尝试使用Lock。

Test.java

运行结果为:

三、总结

个人认为本文最重要的一点是“类锁”的概念。

我在知乎上看了一些关于“synchronized原理”文章,上面提到“类锁”、“对象锁”只是概念,并不是真实存在的。想要理解synchronized的实现机制,还要继续深入下去。