Synchronized 是并发编程中重要的使用工具之一
前言 JVM 自带的关键字,可在需要线程安全的业务场景中使用,来保证线程安全。
用法
按照锁的对象区分可以分为对象锁和类锁
按照在代码中的位置区分可以分为方法形式和代码块形式
对象锁 锁对象为当前 this 或者说是当前类的实例对象
1 2 3 4 5 6 7 8 9 10 11 // 对象锁方法形式 public synchronized void method() { ... } // 对象锁代码块形式 public void method() { synchronized (this) { ... } }
类锁 锁的是当前类或者指定类的Class对象。
一个类可能有多个实例对象,但它只可能有一个Class对象。
1 2 3 4 5 6 7 8 9 public static void synchronized method() { System.out.println("我是静态方法形式的类锁"); } public void method() { synchronized(*.class) { System.out.println("我是代码块形式的类锁"); } }
简单举例 可以参看深入理解synchronized关键字 、Java并发编程:Synchronized及其实现原理 。
原理也可以参看上面两个文章。
总结 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待;
每个实例都对应有自己的一把锁,不同实例之间互不影响;
锁对象是*.class以及synchronized修饰的static方法时,所有对象共用一把类锁;
无论是方法正常执行完毕或者方法抛出异常,都会释放锁;
使用 synchronized 修饰的方法都是可重入的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class SynchronizedRecursion { int a = 0; int b = 0; private void method1() { System.out.println("method1正在执行,a = " + a); if (a == 0) { a ++; method1(); } System.out.println("method1执行结束,a = " + a); } private synchronized void method2() { System.out.println("method2正在执行,b = " + b); if (b == 0) { b ++; method2(); } System.out.println("method2执行结束,b = " + b); } public static void main(String[] args) { SynchronizedRecursion synchronizedRecursion = new SynchronizedRecursion(); synchronizedRecursion.method1(); synchronizedRecursion.method2(); } } 结果为: method1正在执行,a = 0 method1正在执行,a = 1 method1执行结束,a = 1 method1执行结束,a = 1 method2正在执行,b = 0 method2正在执行,b = 1 method2执行结束,b = 1 method2执行结束,b = 1
可以看到method1()与method2()的执行结果一样的,method2()在获取到对象锁以后,在递归调用时不需要等上一次调用先释放后再获取,而是直接进入,这说明了synchronized的可重入性。
当然,除了递归调用,调用同类的其它同步方法,调用父类同步方法,都是可重入的,前提是同一对象去调用,这里就不一一列举了.
参考链接