Synchronized

monitor机制

  1. 在Java中,最基本的互斥同步手段是synchronized关键字,synchronized关键字经过编译之后,会在同步块之前和之后分别形成monitorenter和monitorexit这两个字节码指令,这两个字节码指令都需要一个reference类型的参数来指明要锁定和解锁的对象
  2. synchronized同步块对同一条线程来说是可重入的,不会出现自己把自己锁死的问题。在执行monitorenter指令时,首先要尝试获取对象的锁。如果对象没被锁定,或者当前线程已经拥有了那个对象的锁,把锁的计数器加1,在执行monitorexit指令时会把锁计数器减1,当计数器为0时,锁就被释放。如果获取对象所失败,当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止

使用

  1. 如果synchronized修饰的是实例方法,锁对象是对象实例
  2. 如果synchronized修饰的是类方法,锁对象是Class对象
  3. 如果synchronzied出现在代码块中,看synchronized参数,参数是实例对象或是类对象,锁对象分别对应的是实例对象或类对象,如果参数是一个object,那么以这个object对象作为锁

happens-before关系

根据synchronized规则,线程A释放锁happens-before线程B加锁,又根据传递性得出,线程A执行同步块中代码happens-before线程B执行同步块中代码,根据happens-before的其中一条定义,如果a happens-before b,那么a的执行结果对b可见

内存语义

线程获取锁之后会强制从主内存读取共享变量的最新的值,并将值拷贝到自己的工作内存,释放锁的时候会将值刷新到主内存中

锁优化

CAS

  • 互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步,互斥同步属于一种悲观的并发策略。随着硬件指令集的发展,出现了基于冲突检测的乐观并发策略,是指先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生了冲突,那就再采取其他的补偿措施,这种乐观的并发策略的许多实现都不需要把线程挂起,因此这种同步操作称为非阻塞同步
  • 硬件保证一个从语义上看起来需要多次操作的行为只通过一条处理器指令就能完成,也就是操作和冲突检测这两个步骤具备原子性,CAS(Compare-and-Swap)就是其中一条指令,是现代处理器新增的,有cmpxchg指令完成CAS功能。CAS指令需要有3个操作数,分别数变量的内存地址V,旧的预期值A和新值B。CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行更新,但是无论是否更新了V的值,都会返回V的旧值,上述的处理过程是一个原子操作
  • 在Java API中,如J.U.C包中的整数原子类的一些方法使用了Unsafe类的CAS操作。CAS在语义上存在逻辑漏洞,如”ABA”问题;CAS也可能存在自旋时间过长的问题