java synchronized,不同的输出弹性

为什么输出有差异 . 我有2个案例 . 1.在第一种情况下,我使用静态函数f1和f2

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

  • 第二种情况f1和f2不是静态的

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

回答(2)

2 years ago

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

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

如果您的 class 被称为 MyClass ,那么:

public static synchronized foo() {...}

类似于:

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

同时:

public synchronized foo() {...}

类似于:

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

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

2 years ago

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 上的锁定 .