2

Why is there a difference in output? I have 2 cases:

  1. In first case I use static functions f1 and 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");
    }
    
    Here is my main method body:
    Thread t1 = new Thread(
            new Runnable(){public void run(){f1();}}
    );
    
    Thread t2 = new Thread(
            new Runnable(){public void run(){f2();}}
    );
    t1.start();
    t2.start();
    
    the output is:
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
    
  2. In the second case f1 and f2 are not static:
    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");
    }
    
    the output is so messy:
    AAABABABBBBAAAAAAAAAABBAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBAA
    
kurumkan
  • 2,635
  • 3
  • 31
  • 55

2 Answers2

2

Static synchronized functions synchronize on the class while non-static synchronized functions synchronize on the instance.

This means that when the functions are static they block each other while when they're not (and use different instances) they don't.

If your class is called MyClass then:

public static synchronized foo() {...}

Is similar to:

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

While :

public synchronized foo() {...}

Is similar to:

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

Generally you want to specify what you're synchronizing on (what resource do you want to hold exclusively?) and avoid using the implicit synchronization on the class/instance because of this reason exactly.

Reut Sharabani
  • 30,449
  • 6
  • 70
  • 88
0

static also applies a lock at the class (JLS-8.4.3.6. synchronized Methods says, in part, for a class (static) method, the monitor associated with the Class object for the method's class is used. For an instance method, the monitor associated with this (the object for which the method was invoked) is used). In your case, you could remove the static from the method(s) and synchronize on System.out. Something like

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");
        }
    }
}   

which will force the threads to acquire a lock on System.out before writing.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249