1、类锁
锁住一个类,这个类中的所有带有synchronized的方法使用同一个锁。
比如:
public class CLock{
//静态方法锁,使用的是类锁。以下两个方法使用同一个类锁,不同线程访问这两个方法,需要遵循同步锁执行规则。
public static synchronized void test(){
}
public static synchronized void test2(){
}
public void test3(){
//非静态方法种的代码块,如果用.class类来加锁,也是类锁。和上面的静态方法使用同一个锁。
synchronized(CLock.class){
}
}
}
2.对象锁
一个对象拥有一个锁,相同的类不同的对象有不同的锁。
public class CLock{
//非静态方法锁,使用的是对象锁。相同的CLock实例test和test2使用的是同一个锁。不同实例的相同方法也不是用同一个锁。
public void synchronized test(){
}
public void synchronized test2(){
}
public void test3(){
//非静态方法种的代码块,如果用this来加锁,也是对象锁。和上面的非静态方法使用同一个锁。
synchronized(this){
}
}
}
所以 CLock c1 =new CLock();CLock c2 =new CLock();
c1.test()和c1.test2()、c1.test3使用的是同一个锁。c1.test()和c2.test()使用的是不同的两个对象锁,所以不同的线程可以同时访问c1.test()和和c2.test()。
还有的情况是单独创建一个对象,用来加锁。
比如以下所有方法的synchronized 的锁都不是同一个对象即都不是同一个锁。
public class CLock{
private Object mLock = new Object();
private static Object mLock2 = new Object();
public void synchronized test(){//具体每个CLock实例拥有他们自己的锁。
}
public static void synchronized test2(){//static方法使用类锁。
}
public void test3(){
synchronized (mLock ){//mLock是一个实例,拥有不同的mLock也拥有不同的锁。
}
}
public void test4(){
synchronized (mLock2 ){//mLock2是一个静态变量,不同的CLock也是拥有同一个锁。
}
}
总之,synchronized 的锁是以对象头的形式存储记录的,所以锁只跟锁实例是不是同一个有关,只要使用同一个锁实例,他们就互斥、阻塞。
3.死锁
那么什么情况会出现死锁的情况呢?那就是锁嵌套并且,不同线程执行的锁顺序刚好倒过来。
public class A{
private Object mLock = new Object();
private Object mLock2 = new Object();
public void test(){
synchronized(mLock){
Thread.sleep(1000);
synchronized(mLock2 ){
}
}
}
public void test2(){
synchronized(mLock2 ){
Thread.sleep(1000);
synchronized(mLock){
}
}
}
}
如果thread1执行 test1(),刚好thread2执行test2()。那么就会出现thread1占有mLock锁,需要访问mLock2锁,就需要等待thread2释放mLock2锁。而thread2占有mLock2锁,需要访问mLock锁,就要等待Thread1释放mLock锁。
相当于是我先拿到你手中的梨才能给你苹果,而你一定要先拿到我手中的苹果才能给我梨。双方僵持不下,就死锁了。
4.阻塞
阻塞是从加锁的地方开始的,下面的代码中多个线程会直接访问a()方法,不需要考虑锁的问题,但是只要mLock被一个线程占有,那么其他线程也无法访问b()方法,都是阻塞在加锁位置,无法往下执行。
public class A{
private Object mLock = new Object();
public void test(){
a();
synchronized(mLock){
Thread.sleep(1000);
}
b();
}
}