美文网首页Android基础知识
Synchronized的四大用法和区别

Synchronized的四大用法和区别

作者: Magic旭 | 来源:发表于2019-06-02 13:44 被阅读25次

    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方法就会达到同步执行的效果。


      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

    总结

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

    相关文章

      网友评论

        本文标题:Synchronized的四大用法和区别

        本文链接:https://www.haomeiwen.com/subject/zsgztctx.html