基本使用
如下抢票的代码,如果不加锁,就会出现超卖或者一张票卖给多个人 Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有 【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住
public class TicketDemo {
static Object lock = new Object();
int ticketNum = 10;
public synchronized void getTicket() {
synchronized (this) {
if (ticketNum <= 0) {
return;
}
System.out.println(Thread.currentThread().getName() +"抢到一张票,剩余:" + ticketNum);
// 非原子性操作
ticketNum--;
}
}
public static void main(String[] args) {
TicketDemo ticketDemo = new TicketDemo();
for (int i = 0; i < 20; i++) {
new Thread(() -> {ticketDemo.getTicket();}).start();
}
}
}
Monitor
Monitor
被翻译为监视器,是由
jvm
提供,
c++
语言实现 在代码中想要体现monitor
需要借助
javap
命令查看
clsss
的字节码,比如以下代码:
public class SyncTest {
static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
synchronized (lock) {
counter++;
}
}
}
找到这个类的
class
文件,在
class
文件目录下执行
javap
-
v SyncTest.class
,反编译效果如下:
![](https://img-blog.csdnimg.cn/direct/bec5f2747bef4082826f0dc4812a4745.png)
![](https://img-blog.csdnimg.cn/direct/5d3984db9e364eeeae78b469fe530012.png)
在使用了
synchornized
代码块时需要指定一个对象,所以
synchornized
也被称为对象锁
monitor
主要就是跟这个对象产生关联,如下图
![](https://img-blog.csdnimg.cn/direct/974cea69045a4a7a9de3fddb58ebda93.png)
Monitor
内部具体的存储结构:
- Owner:存储当前获取锁的线程的,只能有一个线程可以获取
- EntryList:关联没有抢到锁的线程,处于Blocked状态的线程
- WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程
具体的流程:
- 代码进入synchorized代码块,先让lock(对象锁)关联的monitor,然后判断Owner是否有线程有
- 如果没有线程持有,则让当前线程持有,表示该线程获取锁成功
- 如果有线程持有,则让当前线程进入entryList进行阻塞,如果Owner持有的线
- 程已经释放了锁,在EntryList中的线程去竞争锁的持有权(非公平)
- 如果代码块中调用了wait()方法,则会进去WaitSet中进行等
参考回答:
- Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持
- 有【对象锁】它的底层由monitor实现的,monitor是jvm级别的对象( C++实现),线程获
- 得锁需要使用对象(锁)关联monitor
- 在monitor内部有三个属性,分别是owner、entrylist、waitset
- 其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的
- 是处于阻塞状态的线程;waitset关联的是处于Waiting状态的线程