基础知识:
synchronized锁可分为对象锁和类锁, 顾名思义对象锁就是给实例对象进行加锁, 类锁则是给类进行加锁
synchronized常见方式如下:
1 对象方法加锁(对象锁)
public synchronized void test(){ //doSomething。。。。。 }
2 静态方法加锁(类锁)
public synchronized static void test(){ //doSomething。。。。。 }
3 对象加锁(对象锁)
Object object = new Object(); public void test(){ synchronized (object){ //doSomeing。。。。 } }
4 方法中给类加锁(类锁)
public void test(){ synchronized (SocketServerTest.class){ //doSomeing。。。。 }
}
思考:
对象锁锁住对象, 若其他方法块需要获取当前对象锁则必须排队等待释放; 类锁(也称为类锁)则是在使用类加锁或静态方法加锁时需要排队
那么问题来了若类锁和对象锁共存是一种什么样的情况呢, 我们给静态方法和普通方法都加上锁
对于以下代码我们可以预测可能会有两种情况
1对象锁和类锁为互斥, 需要排队 预测结果 test1 test2 tStatic1 tStatic2
2对象锁和类锁无关联,各自作用域不同 预测结果 tStatic1 tStatic2 test1 test2
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread t1 = new Thread(()->test.test1());
Thread t2 = new Thread(()->test.test2());
Thread tStatic1 = new Thread(()->Test.testStatic1());
Thread tStatic2 = new Thread(()->Test.testStatic2());
t1.start();
//保证t2在t1之后获取锁
Thread.sleep(300);
t2.start();
//保证tStatic1在t2之后获取锁
Thread.sleep(300);
tStatic1.start();
//保证tStatic2在tStatic1之后获取锁
Thread.sleep(300);
tStatic2.start();
}
public static class Test{
public synchronized void test1() {
//休眠5秒
try {
Thread.sleep(5*1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("test1");
}
public void test2() {
synchronized (this){
System.out.println("test2");
}
}
public synchronized static void testStatic1(){
//休眠3秒
try {
Thread.sleep(3*1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("testStatic1");
}
public static void testStatic2(){
synchronized (Test.class){
System.out.println("testStatic2");
}
}
}
打印结果:
testStatic1
testStatic2
test1
test2
从以上结果可以看出,对象锁和类锁完全互不影响
注:需要补充的是synchronized为重入锁, 下面一段小示例
public static void main(String[] args) throws InterruptedException { Test test = new Test(); test.testA(); } //inner class public static class Test{ //使用synchronized重入锁 public synchronized void testA(){ System.out.println("testA"); testB(); }
//方法testB 在方法testA 未释放锁的情况下,运行同步代码(同一个线程) private synchronized void testB(){ System.out.println("testB"); } }