怎样在静态方法中使用synchronized

synchronized的实现方式

synchronized的类型可以分为两种:

  1. synchronized method
  2. synchronized block

两者的实现方式是不一样的,jvm规范中写道,编译后的synchronized method 会有一个 ACC_STATIC 的flag,也就是说当jvm的方法调用指令(the method invocation instruction)从the run-time contant pool 中查找到这个method的时候,已经知道它是一个synchronized method,所以锁操作是由方法调用以及返回指令来控制的。

而 synchronized block 的锁是由 monitorentermonitorexit 这两个指令来控制。

可以通过 javap 命令来“反汇编”一下class文件。

java代码:

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 funin fun2 交替出现,就是没有 in fun1

只要运行fun的线程不交出锁,fun1就无法被方法,因为他们都是共享了 Class object 的锁。

时间: 2024-10-26 13:20:57

怎样在静态方法中使用synchronized的相关文章

怎样在静态方法中使用 synchronized

synchronized 的实现方式 synchronized 的类型可以分为两种: synchronized method synchronized block 两者的实现方式是不一样的,jvm 规范中写道,编译后的 synchronized method 会有一个 ACC_SYNCHRONIZED 的 flag,也就是说当 jvm 的方法调用指令(the method invocation instruction)从 the run-time constant pool 中查找到这个 met

Java中利用synchronized关键字实现多线程同步问题

Java 中多线程的同步依靠的是对象锁机制,synchronized关键字就是利用了封装对象锁来实现对共享资源的互斥访问. 下面以一个简单例子来说明多线程同步问题,我们希望在run()方法里加入synchronized关键字来实现互斥访问. package com.clark.thread; public class MyThread implements Runnable{     private int threadId;          public MyThread(int id){

巨人大哥谈Java中的Synchronized关键字用法

巨人大哥谈Java中的Synchronized关键字用法 认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就搞定 了,如果说不考虑性能问题的话,这一操绝对能应对百分之九十以上的情况,若对于性能方面有要求的话就需要额外的知识比如读写锁等等.本文目的先了解透彻synchronized的基本原理. Synchronized的基本使用 Synchronized的作用主要有三个: (1)确保线程互斥的访问同步代码 

面试中关于 synchronized 关键字的 5 连击

1.1 说一说自己对于 synchronized 关键字的了解synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行.另外,在 Java 早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock 来实现的,Java 的线程是映射到操作系统的原生线程之上的.如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成,而操作系

谈谈java中的synchronized关键字

1.synchronized的3种用法 public class Client { public static void main(String[] args) { testSynchronized(); } private static void testSynchronized() { new Foo().sayHello(); } static class Foo { //修饰代码块 void sayHello() { synchronized (this) { System.out.pr

java中的synchronized关键字

参考:http://www.cnblogs.com/devinzhang/archive/2011/12/14/2287675.html 多线程问题的根因: 多线程环境下,对一个对象更改的时候,一个线程A对某个变量做了改变,但是还没改变完成能,就被另外一个线程B抢去了cpu,那么A就不会再执行了,因此导致了数据不一致行为.针对上面引文中银行取款存款的例子,本来存一百取一百正好抵消,但是由于多线程的之间的肆意抢占,有些取存款的操作没有完成,自然导致结果千奇百怪. 关键点: synchronized

静态方法中访问类的实例成员

public class StaticShiLi { static int i=1; int j=2; static void m(){ System.out.println(j);报错 } public static void main(String[] args) { // TODO Auto-generated method stub } } 程序报错,显示无法访问. 疑问:那么怎样在静态方法中访问类的实例成员呢?

在静态方法中访问类的实例成员

1.示例程序 1 public class Example 2 { 3 int x = 3;//类的实例变量,初始化值为3 4 static int y = 4;//类的静态变量,初始化值为4 5 public static void method()//静态方法 6 { 7 System.out.println("实例变量x = " + new Example().x);//在静态方法中访问类的实例变量需首先进行类的实例化 8 System.out.println("静态变

this为何不能用在静态方法中

在类里面的静态方法是不能访问类的非静态成员的,原因很简单,我们要想在本类的方法中访问本类的其它成员,我们需要使用$this这个引用,而$this这个引用指针是代表调用此方法的对象,我们说了静态的方法是不用对象调用的,而是使用类名来访问,所以根本就没有对象存在,也就没有$this这个引用了,没有了$this这个引用就不能访问类里面的非静态成员,又因为类里面的静态成员是可以不用对象来访问的,所以类里面的静态方法只能访问类的静态的属性,既然$this不存在,在静态方法中访其它静态成员我们使用的是一个特