浅学 Synchronized

2019/05/10 Java

Synchronized 是并发编程中重要的使用工具之一


前言

JVM 自带的关键字,可在需要线程安全的业务场景中使用,来保证线程安全。

用法

  • 按照锁的对象区分可以分为对象锁和类锁
  • 按照在代码中的位置区分可以分为方法形式和代码块形式
对象锁

锁对象为当前 this 或者说是当前类的实例对象

// 对象锁方法形式
public synchronized void method() {
	...
}

// 对象锁代码块形式
public void method() {
	synchronized (this) {
		...
	}
}
类锁

锁的是当前类或者指定类的Class对象。

一个类可能有多个实例对象,但它只可能有一个Class对象。

public static void synchronized method() {
    System.out.println("我是静态方法形式的类锁");
}

public void method() {
    synchronized(*.class) {
        System.out.println("我是代码块形式的类锁");
    }
}

简单举例

可以参看深入理解synchronized关键字Java并发编程:Synchronized及其实现原理

原理也可以参看上面两个文章。

总结

一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待;

每个实例都对应有自己的一把锁,不同实例之间互不影响;

锁对象是*.class以及synchronized修饰的static方法时,所有对象共用一把类锁;

无论是方法正常执行完毕或者方法抛出异常,都会释放锁;

使用 synchronized 修饰的方法都是可重入的

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的可重入性。

当然,除了递归调用,调用同类的其它同步方法,调用父类同步方法,都是可重入的,前提是同一对象去调用,这里就不一一列举了.


参考链接

Search

    Table of Contents