怎样在静态方法中使用 synchronized
2015-11-09 17:53
411 查看
synchronized 的实现方式
synchronized的类型可以分为两种:
synchronized method
synchronized block
两者的实现方式是不一样的,jvm 规范中写道,编译后的 synchronized method 会有一个 ACC_SYNCHRONIZED 的 flag,也就是说当 jvm 的方法调用指令(the method invocation instruction)从 the run-time constant pool 中查找到这个 method 的时候,已经知道它是一个synchronized method,所以锁操作是由方法调用以及返回指令来控制的。
而 synchronized block 的锁是由
monitorenter和
monitorexit这两个指令来控制。
可以通过 javap 命令来“反汇编”一下 class 文件。
public class StaticMethodTest { public static synchronized void staticMethod() { } public static void staticMethod1() { synchronized (StaticMethodTest.class) { // ... } } public void memberMethod() { } }
编译成 class 文件后执行
javap -verbose StaticMethodTest
两个静态方法的输出结果分别为
public static synchronized void staticMethod(); descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED Code: stack=0, locals=0, args_size=0 0: return LineNumberTable: line 2: 0 public static void staticMethod1(); descriptor: ()V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=0 0: ldc #2 // class StaticMethodTest 2: dup 3: astore_0 4: monitorenter 5: aload_0 6: monitorexit 7: goto 15 10: astore_1 11: aload_0 12: monitorexit 13: aload_1 14: athrow 15: return Exception table: from to target type 5 7 10 any 10 13 10 any
其实不管静态方法还是成员方法,
synchronized的实现方式都是一样的,那么类和对象究竟有什么关系呢?
类和对象
首先要了解的就是类究竟是怎么来的。JVM 拿到编译器编译好的 class 文件后,首先会把文件载入到内存中,class 文件当然会有自己的格式,所以需要由 ClassLoader 来解析文件的内容,这个解析出来的内容会用一个
Class类的实例 - Class object 来表示,这个 object 可以通过 Java 的
ClassName.class来获取。
也就是说,Class object 是一个
Class类型的实例(instance),而对象是一个 ClassName 的 instance。Class 和 ClassName都是类型,ClassName是由
class关键字定义的,而Class是内置类型。
因此成员方法的synchronized method 就等价于 synchronized (this) block,即下面两种方式是等价的。
public synchronized void fun1() { // do something here }
public synchronized void fun2() { synchronized (this) { // do something here } }
成员方法是属于
this,而静态方法是属于 Class Object,那么静态方法的 synchronized method 也就等价于下面这种形式的 synchronized block 了。
public static synchronized void fun2() { synchronized (ClassName.class) { // do something here } }
验证代码
定义了三个静态方法,分别采用不同的锁机制,并且每个方法都是一个死循环。然后再定义三个线程分别执行调用三个方法。import java.util.concurrent.*; public class SynchronizedTest { private static Object lock = new Object(); public synchronized static void fun() { while (true) { System.out.println("in fun"); try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void fun1() { synchronized (SynchronizedTest.class) { while (true) { System.out.println("in fun1"); try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void fun2() { synchronized (lock) { while (true) { System.out.println("in fun2"); try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { new Thread() { @Override public void run() { fun(); } }.start(); new Thread() { @Override public void run() { fun1(); } }.start(); new Thread() { @Override public void run() { fun2(); } }.start(); } }
运行结果就是 in fun 和 in fun2 交替出现,就是没有 in fun1。
只要运行 fun 的线程不交出锁,fun1 就无法被调用,因为他们都是共享了 Class object 的锁。
相关文章推荐
- ios 3D Touch
- js兼容各个浏览器的复制功能
- Axure实现简单的App首页切换功能(Tab切换)
- 利用Opencv读取图片RGB值并存储在txt文件中
- UVALive 3695 Distant Galaxy(枚举)
- 编程之美-寻找数组中的最大值和最小值方法整理
- web for pentester 之xss 篇
- java序列化作用
- 表单验证
- Scenes and Transitions(2)——创建场景
- java异常处理
- hdu 1272 小希的迷宫
- Microsoft、Google、Facebook的erasure code技术进展及系统分析
- 数组合并
- iOS小demo之image图形(简单的image)
- we are the champion!!!!
- hdu 1272 小希的迷宫
- [ActionScript 3.0] AS3实现图像径向转旋效果
- 在VirtualBox虚拟机中运行ubuntu 常见问题汇总
- 常用排序算法总结(简单数组实现,其他类似)