美文网首页
静态方法加锁,和非静态方法加锁区别

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

作者: 忘尘无憾 | 来源:发表于2018-09-13 15:44 被阅读390次

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


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锁机制 之 代码块锁

相关文章

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

    面试的时候说道了单例,又扯到了加锁等。后来面试官问了问静态方法加锁和非静态方法加锁的区别。结果尴尬了,还是自己没有...

  • 给静态方法加锁锁的是类

    给静态方法加锁 效果: 给普通方法加锁 效果:

  • java类锁和对象锁

    java对象锁有两种:对象锁、类锁。 对象锁:在非静态方法上加锁。声明了一个对象锁。类锁:在静态方法上加锁,声明了...

  • Java多线程方法锁机制

    本文主要介绍在多线程中对于普通方法和静态方法加锁调用产生的情况。结论: (1)非静态方法锁默认为this也就是作用...

  • 知识点1、Synchronized同步静态方法和非静态方法总结

    1.Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。 Java中每个对象都...

  • Java基础-线程-锁

    锁的表示 Java里的锁,主要都是对对象进行加锁,如普通的synchronized非静态方法,就是对当前执行方法的...

  • C#笔记二

    一. 静态方法,静态类 (static) 静态和非静态区别 在非静态类(public class)中,既可以有实例...

  • synchronized关键字最主要的三种使用方式

    修饰实例方法,作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁 修饰静态方法,作用于当前类对象加锁,进...

  • 静态方法与非静态方法的区别

    静态方法static(类型方法)和 非静态方法(实例方法)的区别:一、调用对象、引用变量不同;二、调用方法不同;三...

  • PHP高效率写法

    尽量静态化: 静态方法和非静态方法的效率主要区别在内存: 静态方法在程序开始时生成内存,实例方法在程序运行中生成内...

网友评论

      本文标题:静态方法加锁,和非静态方法加锁区别

      本文链接:https://www.haomeiwen.com/subject/kugigftx.html