您的位置 首页 java

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

synchronized 基础特点:

synchronized锁是可重入的,且在父子类继承中同样适用;

synchronized锁在遇到异常时自动释放锁;

synchronized锁的同步化不可以继承;

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

1、非 线程安全 的高发区

1.1、 多线程 下的 全局变量

1.2、多线程下的未同步的方法

1.3、多线程下的未进行合理同步的方法

本篇主要介绍synchronized的使用技巧,主要针对的情况是1.2和1.3。

要点:只有共享资源的读写(比如 java 读写锁 ,仅读读不需要独占同步,读写,写写,写读均需要独占式同步)操作才需要同步化,如果不是共享资源,则不需要进行多余的同步,这也涉及到锁的粒度问题,后面我再细聊。

synchronized是java中使用的较多的同步关键字,且一直被不断优化。使用synchronized较为简单,不像 Lock 那样需要手动释放锁,虽然失去了一定的灵活性,但对大多数情况下,synchronized还是明智的选择。下文会着重介绍synchronized的使用技巧。

2、synchronized修饰对象方法

2.1、 当多个 线程 同时访问同一个对象的同步方法时,是线程安全的,注意一定是同一个对象,如果创建下图中的两个MyObject类并分别在两个线程的run方法中调用methodA方法,就是非线程安全的了,因为synchronized关键字获取的为对象锁。

如下面图1所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图1

2.2、 在同一个实例对象中,synchronized关键字仅对加了synchronized关键字的方法)会保证线程安全,而对同一个实例对象中的未加synchronized关键字方法不保证线程安全。

如下面图2所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图2

注:在多线程情况下,同一个MyObject对象的methodA方法是线程安全的,而methodB则是非线程安全的。

2.3、 在同一个实例对象中,如果多个方法都被synchronized关键字修饰,则该实例对象中的多个方法之间是同步的,需要等待上一个方法执行结束后下一个获得该对象锁的方法才可以执行,这也正说明了synchronized关键字获得是对象锁,多个方法会争夺同一个对象锁。

如下面图3所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图3

注:方法A和方法B的执行是有序的,先获得对象锁的方法先执行,另一个方法会在该方法执行完毕再执行。

3、 synchronized修饰 静态方法

synchronized修饰静态方法时,持有的锁为类锁,在这种情况下,无论创建多少对象,都共同持有同一个锁即类锁。

如下面图4所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图4

3.1、 两个静态方法同时加synchronized时,会发生阻塞。

如下面图5所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图5

3.2、 一个静态方法一个动态方法,同时加synchronized,不会发生阻塞,原因是一个是静态方法的synchronized持有的是类锁,动态方法持有的synchronized是对象锁。

如下面图6所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图6

3.3、 同步synchronized(class)和直接使用synchronized修饰静态方法效果一样,都是获得类锁,而不是对象锁。

如下面图7所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图7

4、 synchronized结合静态内部类

4.1、 synchronized(this)的情况下

当多个并发线程访问同一个对象的synchronized(this)同步代码块时,各个线程是依次执行的,即该对象的同步代码块中的部分是线程同步的。synchronized同步代码块提升一定的效率。

如下面图8所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图8

结合上面图8中的代码,当一个线程访问该对象的synchronized同步代码块时,其他线程仍然可以访问该对象非synchronized同步代码块中的内容。且能符合我们对线程同步的预期,即synchronized同步代码块持有当前调用对象的锁,且为同步的。

注:当一个线程访问该对象的一个synchronized(this)同步代码块时,其他线程对该对象所有其他的synchronized(this)同步代码块的访问将被阻塞,因为synchronized(this)中的this获取的是整个对象的对象锁。

如下面图9所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图9

方法1和方法2会依次执行。同理,下面图10中的三个方法也是依次执行的:方法3为synchronized修饰的整个方法,而方法1和方法2为synchronized(this)同步代码块。

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图10

4.2、 synchronized(非this)的情况下

使用synchronized(非this)同步代码块时,同一个实例对象可以有多个synchronized(非this)同步代码块,当synchronized(非this)中非this对象相同时,多个synchronized(非this)代码块中的代码具有阻塞性,当非this对象不同时,多个synchronized(非this)代码块分别具有同步特性,相互之间不会出现阻塞。

如下面图11所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图11

下面图12中两个synchronized块持有不同的锁,故不会发生阻塞,方法A持有anString锁,方法B持有anString2锁;

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图12

下面图13中第一个方法持有该对象的对象锁,第二个方法持有anString锁;

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图13

注:

4.3、 当多个线程同时执行synchronized(x){}同步代码块时,呈同步效果,各个synchronized(x){}块会发生阻塞;

如下面图14所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图14

4.4、 当其他线程执行x对象中的synchronized同步方法或synchronized(this)同步代码块时,呈同步效果。

如下图15、图16、图17所示:

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图15

Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

图16

图17

4.5、 如果其他线程调用未加synchronized的方法时,不会发生同步。

注:字符串一般不用于synchronized的锁对象,因为string常量池会产生出乎意料的锁同步和阻塞现象。另外如果锁对象放入缓存或者map后,如果被另一个synchronized所持有,也会发生同步或者阻塞。

5 、synchronized结合内部类

本质上和上述一致,只是将判断锁对象以及使用synchronized位置变换了下而已,只要找到正确的锁对象以及共享数据,就可以轻易的对同步是否合理及是否需要改进进行判断。

参考:java多线程核心编程技术

持续更新完善中……关注有惊喜,共同学习

文章来源:智云一二三科技

文章标题:Java synchronized 各种操作要点-对象锁类锁this锁非this锁等

文章地址:https://www.zhihuclub.com/186457.shtml

关于作者: 智云科技

热门文章

网站地图