Threads - output desynchronized

0

What is the difference between the first and second codes? Why, seeing the first one, the outputs come out messy or repeated and in the second they turn out well? In the first, the syncronized method is that of 'Person', and having the same instance for the two threads, I do not understand why the outputs go wrong or repeated.

 public class Main {

            public static void main(String[] args) {

                BolsaPersonas bolsa = new BolsaPersonas();

                Thread thread = new Thread(bolsa);
                Thread thread2 = new Thread(bolsa);
                thread.start();
                thread2.start();


            }

        }

        class BolsaPersonas implements Runnable {

            Persona persona = new Persona();

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

            public synchronized void incrementar() {
                for (int i=0;i<5000;i++) {
                    persona.doStuff();
                }
            }


        }

        class Persona {

            private int id = 1;
            private Object objeto = new Object();


            public void doStuff() {
                System.out.println("Thread: " + Thread.currentThread().getName() + ". ID: " + id);
                id++;
            }

        }




    class BolsaPersonas implements Runnable {

        @Override
        public void run() {
            Persona persona = new Persona();

            for (int i=0;i<5000;i++) {
                persona.doStuff();
            }

        }


    }

    class Persona {

        private int id = 1;
        private Object objeto = new Object();


        public synchronized void doStuff() {
            System.out.println("Thread: " + Thread.currentThread().getName() + ". ID: " + id);
            id++;
        }

    }
    
asked by MatiEzelQ 07.05.2016 в 16:04
source

1 answer

2

I modified the codes to make it clearer, to see if I understood your problem.

First code (synchronizing in BolsaPersonas.incrementar ):

public class NoMezclaThreads {

    static class BolsaPersonas implements Runnable {
        Persona persona = new Persona();

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

        public synchronized void incrementar() {
            for( int i = 0; i < 5; i++ ) {
                try {
                    Thread.sleep(50);
                } catch(InterruptedException e) {
                    e.printStackTrace();
                }
                persona.doStuff();
            }
        }
    }

    static class Persona {
        private int id = 1;

        public   void doStuff() {
            System.out.println("Thread: " + Thread.currentThread().getName() + ". ID: " + id);
            id++;
        }
    }

    public static void main(String[] args) {
        BolsaPersonas bolsa = new BolsaPersonas();
        Thread thread = new Thread(bolsa);
        Thread thread2 = new Thread(bolsa);
        thread.start();
        thread2.start();
    }
}

Exit:

Thread: Thread-0. ID: 1
Thread: Thread-0. ID: 2
Thread: Thread-0. ID: 3
Thread: Thread-0. ID: 4
Thread: Thread-0. ID: 5
Thread: Thread-1. ID: 6
Thread: Thread-1. ID: 7
Thread: Thread-1. ID: 8
Thread: Thread-1. ID: 9
Thread: Thread-1. ID: 10

Second code (identical, except that it synchronizes in Persona.doStuff ):

public class MezclaThreads {

    static class BolsaPersonas implements Runnable {
        Persona persona = new Persona();

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

        public void incrementar() {
            for( int i = 0; i < 5; i++ ) {
                try {
                    Thread.sleep(50);
                } catch(InterruptedException e) {
                    e.printStackTrace();
                }
                persona.doStuff();
            }
        }
    }

    static class Persona {
        private int id = 1;

        public synchronized  void doStuff() {
            System.out.println("Thread: " + Thread.currentThread().getName() + ". ID: " + id);
            id++;
        }
    }

    public static void main(String[] args) {
        BolsaPersonas bolsa = new BolsaPersonas();
        Thread thread = new Thread(bolsa);
        Thread thread2 = new Thread(bolsa);
        thread.start();
        thread2.start();
    }
}

Exit:

Thread: Thread-0. ID: 1
Thread: Thread-1. ID: 2
Thread: Thread-0. ID: 3
Thread: Thread-1. ID: 4
Thread: Thread-0. ID: 5
Thread: Thread-1. ID: 6
Thread: Thread-0. ID: 7
Thread: Thread-1. ID: 8
Thread: Thread-0. ID: 9
Thread: Thread-1. ID: 10

What is happening here? When you synchronize in a method, you are acquiring a lock on the object to which the method belongs (how to synchronize on this ). And you are saying to Java: "I forbid you to have another thread execute this object " until you have finished with this method ".

In the first case ( NoMezclaThreads ), since there is a single object BolsaPersonas instantiated, and since the synchronized method belongs to this single object, the synchronism works like this: when the second thread wants to run this method it is found that the object is "locked" by the first thread, and it waits until it ends.

In the second case, the synchronism works only at the level of the doStuff method (there will never be two threads executing this method at the same time) but since the two threads are in parallel the method incrementar will be shared among them the execution .

Under no circumstances should duplicate ids be printed, as far as I can see.

    
answered by 07.05.2016 / 16:43
source