Lucas
Lucas

Reputation: 169

Why can my synchronized methods lock on different objects?

I am learning Java concurrency right now. I came across a piece of code like this:

package pac1;

import java.util.*;
import java.util.concurrent.*;

class A1 {
    public void f() {
        synchronized (this) {
            for (int i = 0; i < 5; i++)
                System.out.println("f()");
        }
    }
}

class B1 {
    public void g() {
        synchronized (this) {
            for (int i = 0; i < 5; i++)
                System.out.println("g()");
        }
    }
}

class C1 {
    public void p() {
        synchronized (this) {
            for (int i = 0; i < 5; i++)
                System.out.println("p()");
        }
    }

}

public class V {
    public static void main(String[] args) {
        A1 a = new A1();
        B1 b = new B1();
        C1 c = new C1();
        new Thread() {
            public void run() {
                a.f();
            }
        }.start();
        new Thread() {
            public void run() {
                c.p();
            }
        }.start();
        b.g();
    }

}

Since this code uses different objects to call synchronized methods, I supposed that it would not prevent them from interfering with each other. However, the result is as follows:

f()
f()
f()
f()
f()
g()
g()
g()
g()
g()
p()
p()
p()
p()
p()

BTW, the result is the same using Lock:

package pac1;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class A {
    Lock lock = new ReentrantLock();

    public void f() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++)
                System.out.println("f()");
        } finally {
            lock.unlock();
        }
    }
}

class B {
    Lock lock = new ReentrantLock();

    public void g() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++)
                System.out.println("g()");
        } finally {
            lock.unlock();
        }
    }
}

class C {
    Lock lock = new ReentrantLock();

    public void p() {
        lock.lock();
        try {
            for (int i = 0; i < 5; i++)
                System.out.println("p()");
        } finally {
            lock.unlock();
        }
    }
}

public class Ex16 {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        new Thread() {
            public void run() {
                a.f();
            }
        }.start();
        new Thread() {
            public void run() {
                c.p();
            }
        }.start();
        b.g();
    }

}

Upvotes: 0

Views: 45

Answers (2)

Avneet Paul
Avneet Paul

Reputation: 303

You don't need a lock or synchronized here. Sychronized is used to lock access to shared mutable state. You don't have any shared mutable state to begin with.

You have 3 threads here and nobody can predict the order in which those threads run because of context switching. I don't see a problem.

Upvotes: 1

Ruben
Ruben

Reputation: 771

Actually the loops simply are not long enough hence allowing threads to finalize in the same order they were launched. In order to make apparent that threads do not interfere you may try one of the following approaches :

  • Make the loop to run longer, e.g. 1000 iterations should be more then enough :

    synchronized (this) { for (int i = 0; i < 1000; i++) System.out.println("f()"); }

  • Suspend the threads within the loops but make sure to have different intervals set for each loop :

    synchronized (this) { for (int i = 0; i < 5; i++) { System.out.println("p()"); try { Thread.sleep(3000); } catch (final InterruptedException ex) { // Swallow } } }

So long story short : These locks actually do not interfere.

Upvotes: 0

Related Questions