作用
-
保证原子性(同步代码中的执行不受其他线程干扰),可见性(同步代码中修改后的数据,退出同步后,对其他线程立即可见),有序性(多条线程有序执行)
用法
- 修饰静态方法,相当于对类的class对象加锁。
- 修饰实例方法,相当于对当前实例对象加锁。
- 同步代码块,可以自由选定加锁对象。
知识点
- jdk1.6之前单纯通过monitor实现锁,但因为需要切换内核态执行线程阻塞和线程唤醒等调用系统函数,性能比较差。jdk1.6之后做了优化,锁分为偏向锁、轻量锁、重量锁,底层根据不同的锁状态实现不同的同步机制,其中重量锁即通过monitor实现。1.6之后与reentrantlock性能差不多,synchronized使用相对比较简单,但是synchronized只支持非公平锁,且等锁不可中断。
- 非公平锁。没有先来后到,线程相互竞争,依赖系统调度。非公平锁可能会出现饥饿问题,低优先级的线程一直在阻塞等锁,得不到cpu执行机会,获得锁的线程一直占用锁,或者是wait之后一直没有被唤醒。解决饥饿问题可以用公平锁
- 获取锁的阻塞状态不可中断,因此出现死锁不可中断。
对象组成
- 实例数据。存储类的属性数据,包括父类的数据。
- 填充数据。虚拟机要求对象的起始地址必须是8字节的整数倍,如果对象实例数据不是8字节的整数倍,则会自动填充数据补全。
- 对象头。分为三个部分,mark word存储对象的hashcode、是否是偏向锁、锁标记位、分代年龄等(如果是偏向锁,还会包含一个偏向的线程id,重量级锁包含指向monitor的指针)。klass 指向对象的类信息的指针(当类被加载的时候,jvm会为该类创建instantKlass对象存储在方法区)。如果是数组类型,还会存储数组长度。
- 当对象锁的状态是偏向锁时,mark word存储的是偏向的线程id。当对象的状态是轻量锁时,mark word存储的是线程栈中的lock record指针。当对象锁的状态是重量级锁时,存的是指向堆中的monitor对象指针。
monitor
- monitor是一种程序结构,synchronized基于monitor对象实现同步,每个对象的对象头包含一个指针指向monitor对象,通过一系列机制实现多线程互斥访问共享资源。
HotSpot中monitor结构中的几个主要属性
- head 存储锁对象的mark word
- count 记录线程获取锁的次数
- waiters 处于wait状态的线程数
- waiterSet 获得锁后进入wait状态的线程集合。
- recursions 重入次数
- cxq 竞争队列、所有请求锁的线程都会进入此队列,单向链表结构。
- EntryList 等待获取锁的线程集合。cxq中的线程获取竞争锁的资格时,会进入此队列。
- object 指向该monitor的锁对象
- owner 获取monitor的线程
ObjectWaiter