synchronized和static synchronized的区别

synchronized提供内部锁的机制,防止其它线程同时进入synchronized的代码块。synchronized由两部分组成:1.锁对象的引用;2.锁保护的代码块。 

对锁对象引用的不同,是static synchronized和synchronized最大的区别:

public class SynchronizedTester {
    /*
     * testOne()和testTwo()均是对SynchronizedTester这个类的对象(实例)加上锁
     * 也就是锁对象的引用是SynchronizedTester这个类的对象(实例)
     * 两种写法基本等价
     */
    private synchronized void testOne(){
        //do something...
    }
    private void testTwo(){
        synchronized(this){
            //do something...
        }
    }
}
public class SynchronizedStaticTester {    
    /*
     * testOne()和testTwo()则是对SynchronizedTester这个类加上锁
     * 也就是锁对象的引用是SynchronizedTester这个类,不再是类的对象或类的实例
     * 两种写法基本等价
     */
    private static synchronized void testOne(){
        //do sth.
    }
    private static void testTwo(){
        synchronized (SynchronizedStaticTester.class) { //Notice: Not this!
            // do sth.
        }
    }
}

synchronized的范围是某个类的对象/实例,防止多个线程同时访问同一个类对象/实例的synchronized代码块。 
static synchronized地方范围是某个类,防止多个线程同时访问这个类的synchronized代码块。
实例:

public class A {
    private static boolean isTrue;
    public static synchronized void staticWrite(boolean b){
          isTrue = b;
    }
    public static synchronized boolean staticRead(){
          return isTrue;
    }
    public synchronized void write(boolean b){
          isTrue = b;
    }
    public synchronized boolean read(){
          return isTrue;
    }
}
问题:

线程1访问A.staticWrite(true)方法时,线程2能访问A.staticRead()方法吗?
线程1访问new A().staticWrite(false)方法时,线程2能访问new A().staticRead()方法吗?
线程1访问A.staticWrite(false)方法时,线程2能访问new A().staticRead()方法吗?
答案是都不能。因为无论A创建多少个对象或实例,任一对象调用staticWrite(),或类直接调用staticWrite(),锁对象的引用都是A.class。也就是只要调用staticWrite方法,都会对A.class加锁,而staticRead()需要获得的锁对象也正是A.class,因此会出现阻塞。所以线程2无法访问A.staticRead()方法。

A a=new A(); 线程1访问a.write(false)方法,线程2能访问a.read()方法吗?
A a=new A(); A b=new A();线程1访问a.write(false)方法,线程2能访问b.read()方法吗?
题目1答案是不可以,理由与上面类似。a.write()对类A的对象a加了锁,而a.read()需要获得的锁对象也刚好是a,所以线程2无法访问a.read()。 
题目2答案是可以,a.write()对类A的对象加了锁,而b.read()需要获得的锁对象则是b,两者无冲突。b.read()能顺利获得锁,并访问read()方法。

pulbic class Something(){
    public synchronized void isSyncA(){}
    public synchronized void isSyncB(){}
    public static synchronized void cSyncA(){}
    public static synchronized void cSyncB(){}
}
有Something类的两个实例x与y,那么下列组方法何以被1个以上线程同时访问呢
a.   x.isSyncA()与x.isSyncB() 
b.   x.isSyncA()与y.isSyncA()
c.   x.cSyncA()与y.cSyncB()
d.   x.isSyncA()与Something.cSyncA()
有了上面的知识,很容易判断a,c不能,而b可以。d稍微分析一下,也可以确定可以被1个以上线程同时访问,因此x.isSyncA()锁的是Something的对象x,而Something.cSyncA()锁的是Something.class。

总结:

对于实例同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前对象的Class对象。
对于同步方法块,锁是Synchonized括号里配置的对象。
最后要留意的是:synchronized并不能继承,子类覆盖父类synchronized方法时,一定也要在前面加上synchronized关键字;但子类未重写该方法,实例化子类,调用对应方法,也会加锁。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值