Synchronized的四大用法和区别
2019-06-02 本文已影响25人
Magic旭
Synchronized(同步锁)
本来想用单元测试写case的,但是发现单元测试不支持Sleep操作,无奈下只能回到App上运行打log输出了。让我们回到正题,探讨常用的Synchronized四大用法。
Synchronized四大用法(Java与Kotlin版本)
- synchronized修饰普通方法,Kotlin对应的是@Synchronized注解类。
- synchronized修饰静态方法,Kotlin对应的是@Synchronized注解类。
- synchronized(this),Kotlin对应的是synchronized(this)
- synchronized(xxx.class),Kotlin对应的是synchronized(xxx::class.java)。
注意:以下都是Kotlin代码,只需要执行test方法,就能得到对应输出结果。
Synchronized修饰普通方法作用与含义
- 作用:Synchronized修饰普通方法就是控制多个线程访问同一个变量对应 Synchronized 修饰的方法时候达到同步效果;特别注意是同一个变量,如果多个线程访问非同一个变量对应 Synchronized 修饰的方法时候是异步执行的,无法达到同步效果。
- 含义:变量锁,只针对同个变量生效。
- 代码如下
//
class TestLock {
fun test(){
val mLock = LockTest()
//如果是不同变量,那就是异步执行了
// val mLock2 = LockTest()
val mThreadA = ThreadA()
mThreadA.myLock = mLock
val mThreadB = ThreadB()
mThreadB.myLock = mLock
// mThreadB.myLock = mLock2
mThreadA.start()
mThreadB.start()
MyLog.i("game is start")
}
class ThreadA: Thread() {
var myLock:LockTest? = null
override fun run() {
myLock?.lockTest()
MyLog.i("ThreadA is coming")
}
}
class ThreadB: Thread(){
var myLock:LockTest? = null
override fun run() {
myLock?.lockTest()
MyLog.i("ThreadB is coming")
}
}
class LockTest{
//修饰普通方法
@Synchronized fun lockTest(){
MyLog.i("lock is Start")
Thread.sleep(1000)
MyLog.i("lock is End")
}
}
}
-
输出结果
因为ThreadA和ThreadB持有的引用都是同一个变量,所以两个线程调用 lockTest方法就会达到同步执行的效果。
image.png
当然如果上面注解去掉,ThreadA和ThreadB持有不同的变量,那么 lockTest方法的调用就会异步执行。
image.png
Synchronized修饰静态方法作用与含义
- 作用:Synchronized修饰静态方法就是控制多个线程访问同一类对应 Synchronized 修饰的静态方法时候达到同步效果;无论是否为同一变量,都能达到同步的效果。
- 含义:类锁,只要是访问同个类 Synchronized修饰静态方法就会形成同步效果。
- 代码如下
class TestLock2 {
fun test(){
//类锁无论变量是否同一个,都同步执行
val mLock = LockTest()
val mLock2 = LockTest()
val mThreadA = ThreadA()
mThreadA.myLock = mLock
val mThreadB = ThreadB()
// mThreadB.myLock = mLock
mThreadB.myLock = mLock2
mThreadA.start()
mThreadB.start()
MyLog.i("game is start")
}
class ThreadA: Thread() {
var myLock:LockTest? = null
override fun run() {
MyLog.i("ThreadA of Name:${Thread.currentThread().name} is coming")
myLock?.notifyLockTest()
}
}
class ThreadB: Thread(){
var myLock:LockTest? = null
override fun run() {
MyLog.i("ThreadB of Name:${Thread.currentThread().name} is coming")
myLock?.notifyLockTest()
}
}
class LockTest{
//修饰普通方法
companion object {
@Synchronized fun lockTest(){
MyLog.i("currentName:${Thread.currentThread().name} lock is Start")
Thread.sleep(1000)
MyLog.i("currentName:${Thread.currentThread().name} lock is End")
}
}
fun notifyLockTest(){
lockTest()
}
}
}
-
输出结果
输出结果就是会同步执行,ThreadA执行结束之后才到ThreadB执行。无论是把注释回复,两个线程用同个变量,最后结果都如下所示:
image.png
Synchronized(this) 作用与含义
该作用与含义和Synchronized修饰普通方法是一模一样的,请直接看代码与结果。
- 代码如下
class TestLock {
fun test(){
val mLock = LockTest()
//如果是不同变量,那就是异步执行了
// val mLock2 = LockTest()
val mThreadA = ThreadA()
mThreadA.myLock = mLock
val mThreadB = ThreadB()
mThreadB.myLock = mLock
// mThreadB.myLock = mLock2
mThreadA.start()
mThreadB.start()
MyLog.i("game is start")
}
class ThreadA: Thread() {
var myLock:LockTest? = null
override fun run() {
myLock?.lockTest()
MyLog.i("ThreadA of Name:${Thread.currentThread().name} is coming")
}
}
class ThreadB: Thread(){
var myLock:LockTest? = null
override fun run() {
myLock?.lockTest()
MyLog.i("ThreadB of Name:${Thread.currentThread().name} is coming")
}
}
class LockTest{
//修饰普通方法
@Synchronized fun lockTest(){
synchronized(this){
MyLog.i("currentName:${Thread.currentThread().name} lock is Start")
Thread.sleep(1000)
MyLog.i("currentName:${Thread.currentThread().name} lock is End")
}
}
}
}
-
输出结果
同个变量时候,ThreadA执行结束之后才轮到ThreadB执行,为同步执行。
image.png
不同变量时候,ThreadA和ThreadB是异步执行的。
image.png
Synchronized(xxxx.class) 作用与含义
该作用与含义和Synchronized修饰静态方法是一模一样的,请直接看代码与结果。
- 代码
class TestLock2 {
fun test(){
//类锁无论变量是否同一个,都同步执行
val mLock = LockTest()
val mLock2 = LockTest()
val mThreadA = ThreadA()
mThreadA.myLock = mLock
val mThreadB = ThreadB()
mThreadB.myLock = mLock
// mThreadB.myLock = mLock2
mThreadA.start()
mThreadB.start()
MyLog.i("game is start")
}
class ThreadA: Thread() {
var myLock:LockTest? = null
override fun run() {
MyLog.i("ThreadA of Name:${Thread.currentThread().name} is coming")
myLock?.notifyLockTest()
}
}
class ThreadB: Thread(){
var myLock:LockTest? = null
override fun run() {
MyLog.i("ThreadB of Name:${Thread.currentThread().name} is coming")
myLock?.notifyLockTest()
}
}
class LockTest{
//修饰普通方法
companion object {
fun lockTest(){
MyLog.i("currentName:${Thread.currentThread().name} lock is Start")
Thread.sleep(1000)
MyLog.i("currentName:${Thread.currentThread().name} lock is End")
}
}
fun notifyLockTest(){
synchronized(TestLock2::class.java){
lockTest()
}
}
}
}
-
输出结果
无论是否为同个变量,都会为同步执行。因为该修饰属于类锁。
image.png
总结
- synchronized修饰普通方法与synchronized(this)可以简单理解为变量锁,他们只能针对同个变量达到同步执行效果;如果是不同变量就会异步执行。
- synchronized修饰静态方法与synchronized(xxx.class)可以简单理解为类锁,只要调用同个类的加锁方法,都能达到同步执行效果。