目录
1 简介
java语言的关键字,在多线程情况下,可以保证共享资源的安全性,保证同一时刻只有一个线程去访问这个共享资源,其他线程必须等待获取该共享资源的线程执行完毕,才能获取到这个资源。synchronized是非公平的,谁先抢到谁使用。
举个例子:火车站窗口卖票(一个窗口),同一时刻只有一个能去买票,其他人必须等到前一个人买完之后离开才能继续买票,而且卖票的服务人员能时刻知道票的剩余量, 不会出现多卖的情况。
2 用法
synchronized能用到两个地方:
(1):作用到代码块,锁定的是当前变量
public void m1() {
synchronized(o) {
//业务逻辑
}
}
(2):作用到方法上,此时又有两种情况
①:实例方法:锁定的是当前对象
public synchronized void m1(){
//业务逻辑
}
②:静态方法:锁定的是当前类对象
public synchronized static void m1(){
//业务逻辑
}
下面是例子:
锁定的对象只有一个线程能够获取,其他线程阻塞等待。下面举例说明:
public class SynTest {
static Object object =new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (object){
System.out.println(Thread.currentThread().getName()+"获取了线程111");
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+"释放线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
System.out.println("我已经开启线程");
synchronized (object){
System.out.println(Thread.currentThread().getName()+"获取了线程222");
}
}).start();
}
}
结果如下:
说明:Thread-0和Thread-1开始运行,但是由于Thread-0已经把object对象锁定,所以Thread-1只有等到Thread-0线程执行完毕才能得到object对象。
3 原理
在讲述原理之前,先聊聊Monitor对象和对象的内存布局。
3.1 Monitor对象
在HotSpot虚拟机中,Monitor是基于C++的ObjectMonitor类实现的,每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
monitor是线程私有的数据结构,每一个线程都有一个可用monitor列表,同时还有一个全局的可用列表,先来看monitor的内部:
Owner:初始时为NULL表示当前没有任何线程拥有该monitor,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL;
EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor失败的线程。
RcThis:表示blocked或waiting在该monitor上的所有线程的个数。
Nest:用来实现重入锁的计数。
Hash