参考了知乎的文章加深对锁的理解。
主要看了bravo1988的回答。有了以下理解:
synchronized既是加锁也是验权。
先是进行验证是否有权限进行加锁。
然后验权通过后对对象进行加锁。
具体步骤大致如下:
1.检查对象锁状态。结果有3中情况:
1.1 对象未加锁,则验权通过,执行步骤2。
1.2 对象已加锁,并且是本线程加的锁,则验权通过,给对象重入锁,执行步骤2。
1.3 对象已加锁,并且是非本线程加的锁,则验权不通过,等待一段时间(这个时间应该很快,1秒内吧)重新执行步骤1。
2. 对对象进行加锁。然后执行步骤3。
3. 执行后面代码块。然后执行步骤4。
4. 释放锁。如果有重入锁,则-1。
大概流程应该就是这样吧。
synchronized只是一个内置锁的加锁机制,当某个方法或对象加上synchronized关键字后,就表明要获得该内置锁才能执行,并不能阻止其他线程访问不需要获得该内置锁的方法。网上找资料看到上面这句话,以前看来可能不好理解,现在用我的理解来说就是:上面的步骤是在实现有关synchronized关键字代码才会进行验权和加锁。如果有个对象即使使用synchronized锁住了,并且还没释放该锁。但是有另一个线程如果不使用synchronized关键字,是可以对这个对象进行操作的。感觉理解了,描述起来还是很绕口。还是贴下代码吧。
package test;
public class T {
public synchronized void m1(){
System.out.println("m1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m1结束调用");
}
public void m2() {
System.out.println("m2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m2结束调用");
}
public static void main(String[] args) throws InterruptedException {
T t = new T();
Thread test1 = new Thread(new Runnable() {
public void run() {
t.m1();
}
}, "test1");
Thread test2 = new Thread(new Runnable() {
public void run() {
//如果调用m2时没对t加synchronized关键字,则不会进行验权和加锁,此时即使t被线程1加锁了,线程2还是会直接调用m2方法,而不会阻塞等到线程1释放锁才执行m2.
t.m2();
// synchronized(t){
// t.m2();
// }
}
}, "test2");
test1.start();
//确保m1先执行
Thread.sleep(500);
test2.start();
}
}
运行结果:
然后就是理解synchronized使用时,锁的对象到底是什么。
1.直接锁对象(对象锁)。如下面这种情况,锁的对象就是object。
synchronized( object ){}
2.锁方法(也叫对象锁)。如下面这种情况,调用object.method() 方法时,锁的就是object。
synchronized method(){}
3.锁静态方法(类锁)。如下面这种情况,调用MyTest.method() 方法时,锁的就是MyTest.class对象。
synchronized static method(){}