静态方法加锁,和非静态方法加锁区别

面试的时候说道了单例,又扯到了加锁等。后来面试官问了问静态方法加锁和非静态方法加锁的区别。结果尴尬了,还是自己没有太动脑筋,其实挺容易能够想到的。


static方法调用方式是通过class.fun,而非static方法调用是先new出这个对象,再调用

static synchronized类锁synchronized对象锁

  • 对象锁(又称实例锁,synchronized):该锁针对的是该实例对象(当前对象)。
    synchronized是对类的当前实例(当前对象)进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。
    每个对象都有一个锁,且是唯一的

  • 类锁(又称全局锁,static synchronized):该锁针对的是类,无论实例出多少个对象,那么线程依然共享该锁。
    static synchronized是限制多线程中该类的所有实例同时访问该类所对应的代码块。(实例.fun实际上相当于class.fun

pulbic class Something(){
       // 非静态方法加锁
       public synchronized void isSyncA(){}
 
       public synchronized void isSyncB(){}
 
       // 静态方法加锁
       public static synchronized void cSyncA(){}
 
       public static synchronized void cSyncB(){}
 
}

假如有Something类的两个实例 Something x = new Something()
Something y = new Something() ,如果用多线程进行下述访问

  • x.isSyncA()
    在多个线程同时访问该方法,显然同实例对象加锁,因此会线程同步,不会被同时访问,有约束

    xThread1: 1
    xThread1: 2
    xThread1: 3
    xThread2: 1
    xThread2: 2
    xThread2: 3
    
  • x.isSyncA()与x.isSyncB()
    这里就要说道,每个对象都有且只有一个锁
    假设分配的一个对象空间(new了一个对象),里面有多个方法,相当于空间里面有多个小房间,如果我们把所有或部分的小房间都加锁(synchronized),因为这个对象只有一把钥匙,因此同一时间只能有一个人打开一个小房间,然后用完了还回去,再由JVM 去分配下一个获得钥匙的人。
    所以此处,都是对同一个实例的synchronized域访问,因此不能被同时访问,有约束

  • x.isSyncA()与y.isSyncA()
    不同的实例对象会生成不同的对象锁(对象锁对于不同的对象实例没有锁的约束),因此两者互不影响,可以同时访问(运行时成交替输出),无约束

  • x.cSyncA()与y.cSyncB()
    x.cSyncA()与y.cSyncB()相当于是Something.cSyncA()与Something.cSyncB()
    对于类锁,相当于将所有实例对象共享了这一唯一锁,因此即便是不同实例对象之间,仍然会被限制。所以不能被同时访问,有约束

  • x.isSyncA()与x.cSyncA()(相当于Something.cSyncA())
    这是一种较为特殊的情况,加锁的实例对象方法与加锁的类方法由于锁定(lock)不同这一原因,各自管自己的,因此并无约束,可以同时被访问到,无约束
    类锁和对象锁是两个不一样的锁,控制着不同的区域,两者互不干扰。
    在线程获得对象锁的同时,也可以获得该实例的类锁,即同时获得两个锁,这是允许的。

总结:

  • 一个锁的是类对象,一个锁的是实例对象。
  • 若类对象被lock,则类对象的所有同步方法(static synchronized func)全被lock。
  • 若实例对象被lock,则该实例对象的所有同步方法(synchronized func)全被lock。

synchronized方法与synchronized代码块的区别

synchronized methods() {}synchronized (this) {} 之间并没有什么区别。只是前者便于阅读理解,而后者可以更精确的控制冲突限制访问区域,有时候表现得更加高效。

synchronized代码块获得的是一个对象锁,锁住的同样是整个对象。

    public void test4() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
        }
        System.out.println();
        synchronized (this) {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName() + " s: " + i);
            }
        }
    }

比如在上述代码中,假设有两个线程访问该方法。

  • 当A线程访问对象的synchronized(this)代码块的时候,B线程依然可以访问对象方法中其余非synchronized块的部分。
  • 当A线程进入对象的synchronized(this)代码块的时候,B线程如果要访问这段synchronized块,那么访问将会被阻塞。
// 运行结果
thread2 : 0
thread1 : 0
thread2 : 1
thread1 : 1
thread2 : 2
thread1 : 2


thread1 s: 0
thread1 s: 1
thread1 s: 2
thread2 s: 0
thread2 s: 1
thread2 s: 2

由上可知,从执行效率的角度考虑,有时候并不需要将整个方法都加上synchronized,而是可以采取synchronized代码块的方式,对会引起线程安全问题的那部分代码进行synchronized就可以了。

:由上述知道,synchronized方法和synchronized代码块没有太大区别,所以假设线程A访问了对象的X方法中的synchronized代码块部分,线程B访问同一对象的Y方法中的synchronized方法/代码块,都会被堵塞。

synchronized(非this对象)

上述都是使用synchronized(this)的格式来同步代码块,但JAVA还支持对"任意对象"作为对象监视器来实现同步的功能。这个"任意对象"大多数是实例变量及方法的参数,使用格式为synchronized(非this对象)

其实同理,锁住的不是当前实例对象,而是放入synchronized(非this对象)中的非this对象,即对该对象进行加锁。

优点

如果在一个类中有很多synchronized方法,这时虽然能实现同步,但会受到阻塞,从而影响效率。

但如果同步代码块锁的是非this对象,则synchronized(非this对象)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,大大提高了运行效率。

注:synchronized(非this对象),这个对象如果是实例变量的话,指的是对象的引用,只要对象的引用不变,即使改变了对象的属性,运行结果依然是同步的。

参考:
Synchronized(对象锁)和Static Synchronized(类锁)的区别
java的静态方法加锁与一般方法加锁
java 多线程9 : synchronized锁机制 之 代码块锁

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容