Java多线程之synchronized关键字

  • 目录
    • 前言
    • 场景
    • 知其所以然
    • 注意
    • 小结
前言

关于synchronized这个关键字,笔者这里不想像书中一样,用大量的示例来做演示,希望通过一个例子,作归纳和总结。

场景

已知存在一个类Sample(该类有两个实例对象sampleAlpha,sampleBeta),如下图所示。

public class Sample {

    private Object lock = new Object();

    public synchronized void one() {...}

    public synchronized void two() {...}

    public void three() {...}

    public void four() {
        synchronized (this) {
            ...
        }
    }

    public void five() {
        synchronized (lock) {
            ...
        }
    }

    public static synchronized void six() {
        ...
    }

    public void seven() {
        synchronized (Sample.class) {
            ...
        }
    }

}

下面我们来分不同场景讨论下同步的问题:
同一个实例对象:

1.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的two方法,同步执行。
2.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的three方法,异步执行。
3.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的four方法,同步执行。
4.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的five方法,异步执行。
5.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的six方法,异步执行。
6.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的seven方法,异步执行。
7.线程A执行实例对象sampleAlpha中的six方法,同时线程B执行实例对象sampleAlpha中的seven方法,同步执行。

不同的实例对象:

8.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleBeta中的two方法,异步执行。
9.线程A执行实例对象sampleAlpha中的six方法,同时线程B执行实例对象sampleBeta中的seven方法,同步执行。
……其他类似情况,不一一列举

知其所以然

为什么会出现上述的几种不同情况呢?下面来具体讨论:

第1种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法two的时候,会和线程A竞争该对象的锁,进入等待状态,当线程A释放该对象的锁后,线程B继续持有该锁,继续执行。
第2种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法three的时候,并没有同步锁,不需要竞争,直接执行完毕。
第3种:synchronized(this)获取的也是该对象的锁,参考第1种方式。
第4种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法five的时候,线程B持有的是另外一个对象锁lock,不会和线程A产生竞争,故异步执行。
第5种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法six的时候,此时线程B持有的不是该对象的锁,而是Class类锁,和线程A竞争的不是同一个,故而异步执行。
第6种:同第5种解释。
第7种:同步执行的原因在于静态同步synchronized方法synchronized(class)代码块,都是获取当前Class类的锁,对该类产生的所有对象实例起作用。
第8种:由于线程A和线程B持有的都不是同一个对象的锁,故而异步执行,不会产生同步。
第9种:由于线程A和线程B虽然操作的是不同的对象实例,但是他们持有的都是同一个Class类的锁,故而产生竞争,同步执行。

注意

1.由于常量池的原因,大多数情况下synchronized代码块都不要使用String作为锁对象,最好使用new Object()实例化一个对象。
2.关键字synchronized不具有继承性,但是可以在子类中标记该关键字,在父子继承关系中,实现可重入锁。
3.当线程执行出现异常时,其所持有的锁会自动释放。

小结

从上面的几个例子,我们明白了,synchronized修饰方法和synchronized(this)获取的都是当前实例对象的锁,synchronized静态方法和synchronize(class)获取的是Class类的锁,这是两种不同的锁,而要想多线程产生同步,则多个线程竞争的必须是同一个锁

牢记这一点,做一个心中有锁的人。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值