(二)1. 同步锁-synchronize

一. 定义

   对于每一个对象,有且仅有一个同步锁;不同的线程能共同访问该同步锁。但是,在同一个时间点,该同步锁能且只能被一个线程获取到。不同线程对同步锁的访问是互斥的,不同的加锁方式不互斥",协调多个相互关联线程合作完成任务,彼此之间知道对方存在,执行顺序往往是有序的。他是属于独占式的悲观锁,同时属于可重入锁。

二、原理

  进入时,执行 monitorenter,将计数器 +1,释放锁 monitorexit 时,计数器-1; 当一个线程判断到计数器为 0 时,则当前锁空闲,可以占用;反之,当前线程进入等待状态。 含义:(monitor 机制) Synchronized 是在加锁,加对象锁。 对象锁是一种重量锁(monitor), synchronized 的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问 synchronized 区域)、 对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。针对同步锁的升级,会专门出一篇博客。

三、synchronized方法 和 synchronized代码块

  同步方法 (在方法声明上加synchronize):同步方法的锁是固定的this
  同步代码块 (锁的对象可以是任意对象): 同步代码块的锁是任意的对象。
  建议使用同步代码块。因为同步函数的锁唯一的,只能是this,最好使用同步块来减少锁定范围提高并发效率。

四、实例锁 和 全局锁

  实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念)
  全局锁(该锁针对的是类,无论实例多少个对象,那么线程都共享该锁) "全局锁对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)" 同步代码块中锁对象能是任意的对象;多个线程时,用同一个锁对象才能保证线程安全。 同步方法中的锁对象是 this 静态同步方法中的锁对象是 类名.class

一个很经典的示例(通过不同的锁的类型来理解实例锁和全局锁)

pulbic class Something {
    public synchronized void isSyncA(){}
    public synchronized void isSyncB(){}
    public static synchronized void cSyncA(){}
    public static synchronized void cSyncB(){}
}
假设,Something有两个实例x和y。分析下面4组表达式获取的锁的情况。
(01) x.isSyncA()与x.isSyncB() 
(02) x.isSyncA()与y.isSyncA()
(03) x.cSyncA()与y.cSyncB()
(04) x.isSyncA()与Something.cSyncA()
(01) 不能被同时访问。因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!
(02) 可以同时被访问。因为访问的不是同一个对象的同步锁,x.isSyncA()访问的是x的同步锁,而y.isSyncA()访问的是y的同步锁。
(03) 不能被同时访问。因为cSyncA()和cSyncB()都是static类型,x.cSyncA()相当于Something.isSyncA(),y.cSyncB()相当于Something.isSyncB(),因此它们共用一个同步锁,不能被同时反问。
(04) 可以被同时访问。因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。

五、同步锁的适用场景

   一般用于对同一资源竞争比较小的情况下。

六、什么时候释放锁

  1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;

  2)线程执行发生异常,此时JVM会让线程自动释放锁。

猜你喜欢

转载自www.cnblogs.com/tianxin945/p/12322661.html