Synchronized的四大用法和区别

Synchronized(同步锁)

本来想用单元测试写case的,但是发现单元测试不支持Sleep操作,无奈下只能回到App上运行打log输出了。让我们回到正题,探讨常用的Synchronized四大用法。

Synchronized四大用法(Java与Kotlin版本)

  1. synchronized修饰普通方法,Kotlin对应的是@Synchronized注解类。
  2. synchronized修饰静态方法,Kotlin对应的是@Synchronized注解类。
  3. synchronized(this),Kotlin对应的是synchronized(this)
  4. 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方法就会达到同步执行的效果。


    14517298-96951cdb4a3006ed.png
    image.png

当然如果上面注解去掉,ThreadA和ThreadB持有不同的变量,那么 lockTest方法的调用就会异步执行。


14517298-92593212c55a5893.png
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执行。无论是把注释回复,两个线程用同个变量,最后结果都如下所示:


    14517298-86fe932519c42d84.png
    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执行,为同步执行。


    14517298-08e89ee297c6146f.png
    image.png

不同变量时候,ThreadA和ThreadB是异步执行的。


14517298-fe8edae5edc0860c.png
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()
            }
        }
    }
}
  • 输出结果
    无论是否为同个变量,都会为同步执行。因为该修饰属于类锁。


    14517298-5b397a974ad19c17.png
    image.png

总结

  1. synchronized修饰普通方法与synchronized(this)可以简单理解为变量锁,他们只能针对同个变量达到同步执行效果;如果是不同变量就会异步执行。
  2. synchronized修饰静态方法与synchronized(xxx.class)可以简单理解为类锁,只要调用同个类的加锁方法,都能达到同步执行效果。

猜你喜欢

转载自blog.csdn.net/weixin_33929309/article/details/90893244