线程
线程是什么?
- 线程由Thread ID, PC 程序计数器, Registers 寄存器和堆栈组成。是CPU使用资源的最小单位。
- 由图可以看出,一个进程中的线程们共享资源和内存,为了不让线程们对共享资源的操作出现混乱,我们需要一个机制来管理,这个机制就是
锁
锁
锁是什么?
根据维基百科,锁是一种同步机制,用于在执行多线程时强行限制线程们对共享资源的访问。
翻译一下来说,假设有个线程叫小明,还有个线程叫小军,他俩同时想上同一个卫生间,总不能让他们共用一个马桶吧,所以小明先进去,把卫生间上锁,等小明完事了,解锁,然后小军再进去,这就保证了同一时刻,只能有一个人使用同一个马桶.
synchronized
What?
synchronized是Java提供的关键字,对一个对象实现线程独占,进行原子操作。
How?
- 方法锁
锁住的是当前对象,所以只有使用同一对象的线程才会受到影响。也就是说,多个对象调用operate()方法,不会收到锁的影响。
如果有多个synchronized修饰的方法,它们会被一起锁住。
public class ClassA {
public synchronized operate(){
}
}
- 对象锁
示例代码锁住的是一个代码块,所以又叫同步代码块锁任何想要使用operate()方法的线程,需要先获得object实例的锁
// 使用在函数中
public class ClassA {
Object obj = new Object();
public operate(){
synchronized(obj) {
// 该块内为原子操作
}
}
}
- 静态锁 不论锁的是静态方法,还是静态对象,还是.class(类锁),因为是静态的,JVM中只存在一个,实现了全局锁定
public class ClassA {
public synchronized static operate(){
}
}
public class ClassA {
static Object obj = new Object();
public operate(){
synchronized (obj) {
}
}
}
public class ClassA {
public operate(){
synchronized (ClassA.class) {
}
}
}
锁的释放
- 被锁住的代码运行完成
- 抛出异常,自动释放
特性
- 不可中断
- 可重入
加锁原理
观察如下代码进行反编译后的字节码:
Object o = new Object();
synchronized (o) {
System.out.println("hello");
}
0 new #2 <java/lang/Object>
3 dup
4 invokespecial #1 <java/lang/Object.<init>>
7 astore_1
8 aload_1
9 dup
10 astore_2
11 monitorenter
...
21 monitorexit
...
30 return
从汇编角度看,monitorenter指令代表加锁,monitorexit指令代表解锁