在Kotlin伴生类中使用@Synchronized的问题记录

记录最近在Kotlin的@Synchronized在伴生类中使用遇到的问题,代码如下。

// Kotlin类
class MyTest {
    companion object {
        @JvmStatic
        @Synchronized
        fun test1(){
            try {
                println("test1 start")
                Thread.sleep(2000L)
                println("test1 end")
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        }
    }

    fun test2(){
        println("test2 start")
        println("test2 end")
    }
}

fun main(args: Array<String>) {
    // 子线程1直接运行同步方法test1
    Thread {
        MyTest.test1()
    }.start()

    // 子线程2中运行同步代码块,同步代码块的锁为伴生类的class
    Thread {
        synchronized(MyTest.Companion::class.java){
            MyTest().test2()
        }
    }.start()
}
// 预期结果:
// test1 start
// test1 end
// test2 start
// test2 end

// 实际结果:
// test1 start
// test2 start
// test2 end
// test1 end

从上面的运行结果可以看出子线程2的同步代码块使用的锁与MyTest.Companion.test1()所使用的锁是不一致的。我曾在子线程2中尝试过使用以下四个参数作为锁都是没办法达到预期效果:

1、MyTest::class

2、MyTest::class.java

3、MyTest.Companion::class

4、MyTest.Companion::class.java

因此,我将MyTest类通过字节码编译成Java类,查看里面的具体情况,发现MyTest.Companion.test1()使用的锁果然和上面几个不一样,Java代码如下。

// 通过字节码翻译成的Java类(已删减,只保留主要代码)
public final class MyTest {
   @NotNull
   public static final MyTest.Companion Companion = new MyTest.Companion((DefaultConstructorMarker)null);

   public final void test2() {
      String var1 = "test2 start";
      System.out.println(var1);
      var1 = "test2 end";
      System.out.println(var1);
   }

   @JvmStatic
   public static final synchronized void test1() {
      Companion.test1();
   }

   public static final class Companion {
      @JvmStatic
      public final synchronized void test1() {
         try {
            String var1 = "test1 start";
            System.out.println(var1);
            Thread.sleep(2000L);
            var1 = "test1 end";
            System.out.println(var1);
         } catch (InterruptedException var2) {
            var2.printStackTrace();
         }
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

1、MyTest内部生成了一个名为Companion的静态类,其内部有一个普通同步方法synchronized test1()

2、MyTest内持有MyTest.Companion类的实例名为Companion

3、MyTest还生成了一个静态同步方法static synchronized test1(),它的作用就是调用MyTest.Companion中的普通同步方法synchronized test1()

根据Java中synchronized关键字的规则可以得知,MyTest.test1()使用的锁是MyTest.class,而MyTest.Companion.test1()使用的锁则是MyTest.Companion的实例Companion

看到这里我们也就知道为什么在kotlin代码的子线程2中使用的那四把锁无法达到我们的预期效果了,我们只需要将锁换成MyTest.Companion即可。

fun main(args: Array<String>) {
    // 子线程1直接运行同步方法test1
    Thread {
        MyTest.test1()
    }.start()

    // 子线程2中运行同步代码块,同步代码块的锁为伴生类的实例
    Thread {
        synchronized(MyTest.Companion){
            MyTest().test2()
        }
    }.start()
}
// 实际结果:
// test1 start
// test1 end
// test2 start
// test2 end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值