Java关键字之synchronized

1.synchronized的概念
synchronized是Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块


2.对synchronized的理解
synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。代表这个方法(或代码块)加锁,相当于不管哪一个线程(例如线程A),运行到这个方法(或代码块)时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法或同步代码块),有的话要等正在使用synchronized方法(或代码块)的线程B(或者C 、D)运行完这个方法(或代码块)后再运行此线程A,没有的话,锁定调用者,然后直接运行。
同步锁依赖于对象,每个对象都有一个同步锁。


3.synchronized 关键字的特性应用

特性 1:

当线程A调用某对象的synchronized方法或者synchronized代码块时,若同步锁未释放,其他线程调用同一对象的synchronized方法或者synchronized代码块时将被阻塞,直至线程A释放该对象的同步锁。

DEMO1,synchronized方法:
Java关键字之synchronized
Java关键字之synchronized
DEMO1输出:
Java关键字之synchronized
DEMO2,synchronized 代码块:
Java关键字之synchronized
DEMO2输出:
Java关键字之synchronized
可见,当同步锁未释放时,其他线程将被阻塞,直至获得同步锁。

而且DEMO1和DEMO2的输出结果是一样的,synchronized方法和synchronized代码块的不同之处在于synchronized方法 作用域较大,作用于整个方法,而synchronized代码块可控制具体的作用域,更精准控制提高效率。(毕竟阻塞的都是时间啊)

DEMO3,仅修改 main 方法:
Java关键字之synchronized
DEMO3输出:
Java关键字之synchronized
同步锁基于对象,只要锁的来源一致,即可达到同步的作用。但对象不一样,则不能达到同步效果。

特性 2:

当线程A调用某对象的synchronized方法或者synchronized代码块时,若同步锁未释放,其他线程调用同一对象的**其他**synchronized方法或者synchronized代码块时将被阻塞,直至线程A释放该对象的同步锁。

DEMO4,仅修改 doOtherThings 方法的修饰:
Java关键字之synchronized
DEMO4输出:
Java关键字之synchronized
可见,synchronized 获得的同步锁并非仅仅锁住代码,而是锁住整个对象。

此时应提及 happens-before 原则,正因 happens-before 原则的存在才有此现象的发生。
happens-before 原则的其中一条:

管理锁定原则:一个 unLock 操作先行发生于后面对同一个锁的 lock 操作

DEMO5,仅修改 doOtherThings 方法:
Java关键字之synchronized
DEMO5输出:
Java关键字之synchronized
DEMO5和DEMO4输出的结果是一直的,因为它们的同步锁来源是一直的,都是本实例自己,所以可以达到同步的效果。
Java关键字之synchronized
DEMO6去掉doOtherThings方法的同步关键字:
Java关键字之synchronized
DEMO6输出:
Java关键字之synchronized
当线程A调用某对象的synchronized方法或者synchronized代码块时,无论同步锁是否释放,其他线程调用同一对象的其他非synchronized方法或者非synchronized代码块时可立即调。


4.实例锁和全局锁

以上DEMO实现的都是实例锁。锁住(作用域)的是具体某一对象实例。

什么是全局锁?

锁住整个 Class,而非某个对象或实例。

注:单例型的实例锁不属于全局锁。

全局锁的实现:

静态synchronized方法

DEMO7:
Java关键字之synchronized
DEMO7输出:
Java关键字之synchronized
static 声明的方法为全局方法,与对象实例化无关,所以 static synchronized 方法为全局同步方法,与对象实例化无关。


synchronized 具体 Class 的代码块
DEMO8:
Java关键字之synchronized
DEMO8输出:
Java关键字之synchronized
synchronized (Counter.class) 获得的同步锁是全局的,static synchronized 获得的同步锁也是全局的,同一个锁,所以达到同步效果。

区分 synchronized (this) 与 synchronized (Class.class)


DEMO9:
Java关键字之synchronized
Java关键字之synchronized
DEMO9输出:
Java关键字之synchronized
synchronized(this)获得的是具体对象实例counter的锁,而synchronized(Counter.class)获得的是全局锁,两把不同的锁,所以不能达到同步效果。