Synchronized 你真的懂吗?

在这里插入图片描述

关于 Synchronized 的原理可以参见 聊聊并发(二)Java SE1.6中的Synchronized

概念

  • 首先要强调的一点 Synchronized 并不是锁它只是一个关键字,他的作用是标记方法或者代码块是同步的。Synchronized 关键字会直接锁住公共内存,保证资源、数据的同步避免竞争。
  • 本质上 Synchronized 锁住的是一个叫 Monitor 的东西,如果一个 Monitor 被 Synchronized 标记,所有访问此 Monitor 的动作都会被阻塞直到 Monitor 被释放掉。
  • 被 Synchronized 标记的代码块执行完毕后会自动释放 Monitor 即解除锁。
  • Synchronzied 是一个很重的方法。

Synchronized 大概可以分为以下几种同步块:

  • 标记实例方法:实例同步方法

    在方法声明的时候加上 Synchronized 关键字,这将告诉 Java 此方法是同步的,此时 Synchronized 的 Monitor 是拥有该方法的对象。所以当前线程可以访问此类的任何实例方法, 而其他线程需要等待 methodA() 结束。

    这样每一个 methodA() 方法都同步在不同的对象上,即该方法所属的实例。如果有多个实例存在,那么一个线程一次可以在一个实例同步块中执行,即一个实例一个线程。

  public class SynchronizedDemo {  
  	/**
     * 此时 synchronized 锁住的是当前对象!
     */
    public synchronized void methodA() {
  		……
    }
  }
  • 标记静态方法 :静态同步方法

    静态方法同步和实例方法同步方法一样,也使用synchronized 关键字。被 static 标记的方法也称类方法,他是属于类的而非具体对象,所以如果 Synchronized 方法标记了静态方法,此时的 Monitor 将会是 SynchronizedDemo 的字节码文件( SynchronizedDemo.class 也就是类对象),在 Java 虚拟机中一个类只有一个类对象,这意味着不管同一个类中的哪个静态同步方法被访问,其他的线程都需等待。即一个字节码文件一个线程。

    对于不同类的静态同步方法,他们的 Monitoer 为各自的字节码文件,所以一个线程可以同时访问不同类中的竟然方法而无需等待。

  public class SynchronizedDemo {   
  		/**
       * staticA 的写法等价于 staticB
       */
      public static synchronized void staticA() {
  
      }
  
      public static void staticB() {
          synchronized (SynchronizedDemo.class){
  
          }
      }
  }
  • 实例方法中标记代码块

      // 此方式将会锁住当前实例
        synchronized (this) {

        }

        // 锁住字节码文件,意味着 SynchronizedDemo 的所有实例都会被锁住
        synchronized (SynchronizedDemo.class) {

        }

        // 锁住指定的实例,这种方式一般用於单独判读
        synchronized (monitor) {

        }
  • 静态方法中标记代码块

  public class SynchronizedDemo {   
  		/**
       * staticA 、staticB 写法等价
       */
      public static synchronized void staticA() {
  
      }
  
      public static void staticB() {
          synchronized (SynchronizedDemo.class){
  
          }
      }
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章