zoukankan      html  css  js  c++  java
  • 探讨Java中static synchronized和synchronized

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

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

     1 public class SynchronizedTester {
     2 
     3     /*
     4      * testOne()和testTwo()均是对SynchronizedTester这个类的对象(实例)加上锁
     5      * 也就是锁对象的引用是SynchronizedTester这个类的对象(实例)
     6      * 两种写法基本等价
     7      */
     8     private synchronized void testOne(){
     9         //do something...
    10     }
    11     private void testTwo(){
    12         synchronized(this){
    13             //do something...
    14         }
    15     }
    16 
    17 }
     1 public class SynchronizedStaticTester {    
     2     /*
     3      * testOne()和testTwo()则是对SynchronizedTester这个类加上锁
     4      * 也就是锁对象的引用是SynchronizedTester这个类,不再是类的对象或类的实例
     5      * 两种写法基本等价
     6      */
     7     private static synchronized void testOne(){
     8         //do sth.
     9     }
    10     
    11     private static void testTwo(){
    12         synchronized (SynchronizedStaticTester.class) { //Notice: Not this!
    13             // do sth.
    14         }
    15     }
    16     
    17     
    18 
    19 }

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

    static synchronized地方范围是某个类,防止多个线程同时访问这个类的synchronized代码块。

    知道区别以后看看题目:

    1.出自并发编程网

     1 public class A {
     2 
     3     private static boolean isTrue;
     4     
     5     public static synchronized void staticWrite(boolean b){
     6           isTrue = b;
     7     }
     8 
     9     public static synchronized boolean staticRead(){
    10           return isTrue;
    11     }
    12     
    13     public synchronized void write(boolean b){
    14           isTrue = b;
    15     }
    16 
    17     public synchronized boolean read(){
    18           return isTrue;
    19     }
    20 }

    问题:

    1. 线程1访问A.staticWrite(true)方法时,线程2能访问A.staticRead()方法吗?
    2. 线程1访问new A().staticWrite(false)方法时,线程2能访问new A().staticRead()方法吗?
    3. 线程1访问A.staticWrite(false)方法时,线程2能访问new A().staticRead()方法吗?

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

    1. A a=new A(); 线程1访问a.write(false)方法,线程2能访问a.read()方法吗?
    2. 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()方法。

    再次总结:

    1. 对于实例同步方法,锁是当前实例对象。
    2. 对于静态同步方法,锁是当前对象的Class对象。
    3. 对于同步方法块,锁是Synchonized括号里配置的对象。

    再看一题,出自日本作者-结成浩的《java多线程设计模式》

    1 pulbic class Something(){
    2          public synchronized void isSyncA(){}
    3          public synchronized void isSyncB(){}
    4          public static synchronized void cSyncA(){}
    5          public static synchronized void cSyncB(){}
    6      }

    有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。

    最后要留意的是:synchronized并不能继承,子类覆盖父类synchronized方法时,一定也要在前面加上synchronized关键字;但子类未重写该方法,实例化子类,调用对应方法,也会加锁

    这篇文章对synchronized关键字做了深入的总结,值得仔细理解。

  • 相关阅读:
    C#客户端和服务端数据的同步传输 (转载)
    静态网页制作教程 (转载)
    C#中将ListView数据导出为excel(转载)
    数据导入Excel时,出现ole error 800AC472这个错误,怎么解决。
    C# 导出dataGridView中的值到Excel
    C#基础知识六之委托(delegate、Action、Func、predicate)
    C#基础知识五之abstract virtual关键字
    C#基础知识四之override和new的区别
    C#基础知识三之new关键字
    C#基础知识二之this关键字
  • 原文地址:https://www.cnblogs.com/techyc/p/2969677.html
Copyright © 2011-2022 走看看