What's wrong with my thread ultilizing synchronized-Java

I started to study tread I saw some examples of java7 and java8 ultilizing lambda, I arrived in a part to ultilize the synchronized that and to leave type a waiting list of threads where the proxima and executed after a finish, I'm testing but I'm not able to run the multithreading what am I doing wrong? the output of the code should be first to T1 then to T2 and finally to T3 but it numca follows the result of when an ir ends next time.

    public class mainThread {

        public synchronized void imprimirValores(String numeroThread) {

            for (int i = 0; i < 20; i++)
                System.out.println(numeroThread + " : " + i);

        }

        public static void main(String[] args) {

            new Thread(() -> {

                new mainThread().imprimirValores("T1");

            }).start();

            new Thread(() -> {

                new mainThread().imprimirValores("T2");

            }).start();

            new Thread(() -> {

                new mainThread().imprimirValores("T3");

            }).start();

        }

    }
Author: Fernando josé, 2017-10-14

2 answers

You created an instance synchronization, since your imprimirValores() method is an instance method. Thus, synchronization will only work for objects or methods of that instance that is accessing the synchronized method.

In your method main() you created 3 threads and each of them with a different instance. Thus, the imprimirValores() method will not synchronize the 3 threads as a single instance, but rather an instance for each thread and its values will not be printed neatly.

For it to work as you want, you would have to have a single instance that makes the call to the synchronized method, as in the following example:

public static void main(String[] args) {
    MainThread mt = new MainThread();

    new Thread(() -> {

        mt.imprimirValores("T1");

    }).start();

    new Thread(() -> {

        mt.imprimirValores("T2");

    }).start();

    new Thread(() -> {

        mt.imprimirValores("T3");

    }).start();

}

Note that this time, we only have a single instance accessing the synchronized method, this way, synchronization will work. But it may happen that there is no order in which thread will be executed first. Sometimes it can be T1, T2, and T3 other times T1, T3, T2 or T2, T1, T3. But the values will be ordered, but the JVM is the one who will decide which of the 3 threads it executes first.

 2
Author: romarcio, 2017-10-14 23:50:22

I won't go too far because I think @romarcio's answer explains it very well. I would just like to leave other alternatives.

Class method

Instead of attaching the method to the instance, you could attach the method to the class as a whole. The method itself uses nothing from the instance variable, so it could already be static since its creation:

public static synchronized void imprimirValores(String numeroThread) {
  for (int i = 0; i < 20; i++)
    System.out.println(numeroThread + " : " + i);
}

If by chance it needed to access some information of the object and still if if you insisted on being a method of the class, you could pass the class as a parameter:

public static synchronized void imprimirValores(mainThread selfObj, String numeroThread) {
  for (int i = 0; i < 20; i++)
    System.out.println(numeroThread + " : " + i);
}

In my example, object properties are accessible via the selfObj parameter.

Class lock Object

Another easy and simple alternative is the existence of an object on which one can make the desired lock. This object needs to be unique for every latch it serves. As we want to serve as a lock here the method on every call, independent of instance, I will define that the lock object is a static field of mainThread, as this is its most obvious location.

public class mainThread {
  private static final Lock lck = new Lock();
  public static synchronized void imprimirValores(String numeroThread) {
    synchronized (lck) {
      for (int i = 0; i < 20; i++)
        System.out.println(numeroThread + " : " + i);
    }
  }
  [... o resto do código ...]

The synchronized block allows you to lock on an object, so that lock can be used at various points in your code.

I used the object of type Lock for Purism. If I'm not mistaken Java allows to use any object as being pivot of synchronized.

 1
Author: Jefferson Quesado, 2017-10-15 04:31:41