Home > Enterprise >  Synchronized method does not work but synchronized block does, why?
Synchronized method does not work but synchronized block does, why?

Time:12-09

public class driver{


public static void main(String[] args) {
    PrintNum firstObjectForThread = new PrintNum(0);  // the argument is not used, ignore it
    firstObjectForThread.startNewThread();

    PrintNum secondObjectForThread = new PrintNum(0);
    secondObjectForThread.startNewThread();

}

This is the class that the driver calls:

public class ClassName implements Runnable{

int variableForUpdate;
private Thread t;
private static ArrayList<Integer> intArray;

public ClassName(int variableForUpdate) {
    super();
    this.intArray = new ArrayList<Integer>();
    this.variableForUpdate = variableForUpdate;
    for (int i = 0; i < 30 ; i  ) {
        this.intArray.add(i);
    }
}

@Override
public void run() {
    runThisWhenThreadStarts();
}


private synchronized void runThisWhenThreadStarts() {
    System.out.println("Started");
    for (int i = 0; i < 30; i  ) {
        System.out.println(intArray.get(i));
    }
}

public void startNewThread() {
    t = new Thread(this);
    t.start();
}

}

If I use block synchronization the following, the output is synchronized:

private void runThisWhenThreadStarts() {
    synchronized (ClassName.class) {
        System.out.println("Started");
        for (int i = 0; i < 30; i  ) {
            System.out.println(intArray.get(i));
        }
    }
}

I have been troubleshooting this for many hours and cannot figure out... Can anyone shed some light please? I also notice if I use the same object to call startNewThread(), the synchronization will work. But I don't understand why.

    PrintNum firstObjectForThread = new PrintNum(0);  // the argument is not used, ignore it
    firstObjectForThread.startNewThread();
    firstObjectForThread.startNewThread();

I want to use two different object from the same class instead of one object calling the method twice (the workaround above).

I am able to use the synchronized methods in another program, with 2 different instances (get and put) :

public class Hello extends Thread {
    int x;
    Coffee x1;
    int threadno;

    Hello(int x, Coffee x1) {
        this.x = x;
        threadno = x;
        this.x1 = x1;
    }

    public void run() {
        switch (x) {
        case 0:
            System.out.println("Start thread "   threadno   " Get");
            break;
        case 1:
            System.out.println("Start thread "   threadno   " Put");
            break;
        }
        ops();
        System.out.println("Stopping thread "   threadno);

    }

    public void ops() {
        x1.get();
    }

    public static void main(String[] args) {
        Coffee c1 = new Coffee();
        Hello get = new Hello(0, c1);
        Hello put = new Hello(0, c1);
        get.start();
        put.start();

    }
}

Hello class will call coffee class:

class Coffee {
    boolean available = false; // indicating there nothing to get.
    // waiting on each other.
    int contents = 55;

    public synchronized int get() {
        System.out.println("Entering Get method "   contents);
        for (int i = 0; i < 30; i  ) {
            System.out.println(i);
            }
        return contents;
    }
}

CodePudding user response:

In the first example, the method acquires the lock on the object instance that the method is called on. The block doesnt do that, instead it acquires the lock on the class.

Taking the lock on the instance has no effect on the other thread, it is a different object. Both threads are acquiring their own lock, which is useless. Neither thread is prevented from doing anything.

Taking the lock on the class means both threads are trying to acquire the same lock. For locking to work the same lock has to be used by both threads.

In the second example the Coffee object is shared by both threads, and both threads are trying to acquire the same lock on the Coffee object. That means the second thread to get to the lock has to block until the lock is released by the first thread, locking successfully keeps the thread out until the first thread is done.

To understand synchronized, keep track of what locks are being acquired.

  • Related