【问题标题】:Static and non-static synchronization, why the output results differ?静态和非静态同步,为什么输出结果不同?
【发布时间】:2016-02-20 19:33:42
【问题描述】:

为什么输出会有差异?我有两种情况:

  1. 在第一种情况下,我使用静态函数f1f2
    public static synchronized void f1() {
        for (int i = 0; i < 100; i++)
            System.out.print("A");
    }
    
    public static synchronized void f2() {
        for (int i = 0; i < 100; i++)
            System.out.print("B");
    }
    
    这是我的主要方法体:
    Thread t1 = new Thread(
            new Runnable(){public void run(){f1();}}
    );
    
    Thread t2 = new Thread(
            new Runnable(){public void run(){f2();}}
    );
    t1.start();
    t2.start();
    
    输出是:
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
    
  2. 在第二种情况下,f1f2 不是静态的:
    public synchronized void f1() {
        for (int i = 0; i < 100; i++)
            System.out.print("A");
    }
    
    public synchronized void f2() {
        for (int i = 0; i < 100; i++)
            System.out.print("B");
    }
    
    输出太乱了:
    AAABABABBBBAAAAAAAAAABBAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBAA
    

【问题讨论】:

    标签: java multithreading static synchronization non-static


    【解决方案1】:

    静态同步函数在类上同步,而非静态同步函数在实例上同步。

    这意味着当函数是静态的时它们会相互阻塞,而当它们不是静态的(并且使用不同的实例)时则不会。

    如果你的班级被称为MyClass 那么:

    public static synchronized foo() {...}
    

    类似于:

    public static foo() {
        synchronized (MyClass.class) {
            // ...
        }
    }
    

    虽然:

    public synchronized foo() {...}
    

    类似于:

    public foo() {
        synchronized (this) {
            // ...
        }
    }
    

    通常,您希望指定要同步的内容(您想独占保留什么资源?)并避免在类/实例上使用隐式同步,正是因为这个原因。

    【讨论】:

      【解决方案2】:

      static 还在类上应用锁(JLS-8.4.3.6. synchronized Methods 部分表示,对于类 (static) 方法,使用与方法类的 Class 对象关联的监视器. 对于实例方法,使用与this(调用该方法的对象)关联的监视器)。在您的情况下,您可以从方法中删除static,并在System.out 上删除synchronize。类似的东西

      public void f1() {
          synchronized (System.out) {
              for (int i = 0; i < 100; i++) {
                  System.out.print("A");
              }
          }
      }   
      
      public void f2() {
          synchronized (System.out) {
              for (int i = 0; i < 100; i++) {
                  System.out.print("B");
              }
          }
      }   
      

      这将强制线程在写入之前获取System.out 上的锁。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多