9 Replies Latest reply on May 29, 2010 10:15 PM by 807580

    Confussion about synchronization

    807580
      Hi!

      I'm training to get a SCJP 5, and i was doing some tests about threads and synchronized classes, but got a very weird result.

      I made a thread class that does two things: modify an arraylist and modify a vector. I start the two variables and create two threads, both do the two operations that i mentioned before.

      In the main class i create another vector and array to compare "what should be" and the results of the concurrency modification.

      I was expecting to see that the arraylist to be a mess, and a vector perfectly modified or at least of the same size after each execution, but none of this happened: both objects were radomly modified and cannot be deterministic.

      What am i doing wrong?

      Thanks in advance.

      The code is below:
      /*
       * To change this template, choose Tools | Templates
       * and open the template in the editor.
       */
      
      package Week4;
      
      import java.util.ArrayList;
      import java.util.Iterator;
      import java.util.Vector;
      import sun.awt.windows.ThemeReader;
      
      /**
       *
       * @author cvielma
       */
      public class ThreadExperiments  extends Thread {
      
          public ArrayList al;
          public Vector vec;
          public static int i=0;
          public static int j=0;
      
          public void setArrayList(ArrayList al){
              this.al= al;
          }
      
          public void loadArrayList(){
             //it should load 5000 registries
             for(int k= i+5000; i<k; i++){
                  al.add(""+i);
              }
      
             //it should delete 5 registries in the range loaded
             for(int k= 0; k<i-1000; k+=1000){
                  al.remove(k);
             }
          }
      
          public void setVector(Vector vec){
              this.vec= vec;
          }
      
          public void loadVector(){
      
             //it should load 5000 registries
             for(int k= j+5000; j<k; j++){
                  vec.add(""+j);
              }
      
             //it should delete 5 registries in the range loaded
             for(int k= 0; k<j-1000; k+=1000){
                  vec.remove(k);
             }
          }
      
          public void run(){
              loadArrayList();
              loadVector();
          }
      
          public static void main(String[] args) throws InterruptedException{
              Vector vec= new Vector();
              ArrayList al= new ArrayList();
              ArrayList guide= new ArrayList();
              ArrayList resAl= new ArrayList();
              Vector resVec= new Vector();
              int i =0;
      
              ThreadExperiments te1= new ThreadExperiments();
              ThreadExperiments te2 = new ThreadExperiments();
      
              te1.setArrayList(al);
              te1.setVector(vec);
              te2.setArrayList(al);
              te2.setVector(vec);
      
              te1.start();
              te2.start();
              
              for(int j=i+10000; i<j; i++){
                  resAl.add(""+i);
              }
      
              i=0;
              for(int j=i+10000; i<j; i++){
                  resVec.add(""+i);
              }
      
              te1.join();
              te2.join();
      
              System.out.println("Al size: "+ al.size());
              System.out.println("Vec size: " + vec.size());
      
              resAl.removeAll(al);
              resVec.removeAll(vec);
              
              System.out.println("Res al:" + resAl);
              System.out.println("Res vec:" + resVec);
      
      
              
      
      
              
      
      
          }
      
      }
        • 1. Re: Confussion about synchronization
          796440
          cvielma wrote:
          What am i doing wrong?
          What you're doing wrong is assuming that that code should produce predictable results.

          I would guess that this results from assuming Vector's built-in synchronization does more than it really does. Perhaps you think that because Vector's methods are synchronized, that once one thread starts working with a Vector, no other thread can touch it until the first thread is "done" with it? Or something like that?

          If that's what you're thinking, you're seriously misunderstanding how syncing works. Vector's add() method, e.g., is synced. That means no other thread can call that method or any other synced method on that Vector concurrently with the execution of that add() call. That's it. As soon as add() is done, another thread can all add(), or any other method it wants.

          In addition, since you cannot control or predict when and how threads get scheduled, you can't know what the end result will be, or expect it to be the same each time.

          If this is not what you were thinking, perhaps you could explain what you thought should happen, and why.

          Edited by: jverd on May 29, 2010 11:07 AM
          • 2. Re: Confussion about synchronization
            807580
            Aaaah ok!

            Yes, i misunderstood that. Been synchronized only means that the operation is "atomic", but no the object itself.

            I don't know why i thought other thing :S

            Really thanks.

            Regards,
            • 3. Re: Confussion about synchronization
              796440
              cvielma wrote:
              Aaaah ok!

              Yes, i misunderstood that. Been synchronized only means that the operation is "atomic", but no the object itself.
              More precisely, entering a synced block or method means a) you obtain the lock associated with a particular object and b) no other thread can obtain that same lock until you either exit the synced block or method, or call wait() on it. Any atomicity that results is a side-effect of this.

              Edited by: jverd on May 29, 2010 2:15 PM
              • 4. Re: Confussion about synchronization
                807580
                Perfect. Really thanks!
                • 5. Re: Confussion about synchronization
                  807580
                  Another question that came to me after this: why if i declare the loadVector() method synchronized (i.e: the vector should be modified correctly) it doesn't work either?

                  Both threads are using the same object that i guess should be locked by this method.

                  Thanks in advance.
                  • 6. Re: Confussion about synchronization
                    796440
                    cvielma wrote:
                    Another question that came to me after this: why if i declare the loadVector() method synchronized (i.e: the vector should be modified correctly) it doesn't work either?

                    Both threads are using the same object that i guess should be locked by this method.
                    Nope, you have two different TE objects.
                    public class TE {
                      public sync void load() {
                        // do stuff with a Vector
                      }
                    }
                    You're not obtaining the Vector's lock. You're obtaining the TE's lock.
                    • 7. Re: Confussion about synchronization
                      807580
                      Thanks!

                      Well i guess i have more study to do about this.
                      • 8. Re: Confussion about synchronization
                        796440
                        Here's a rough outline of how I'd do it:
                        public class TE {
                          public sync void loadVec() {
                            // vector manipulation code
                          }
                        }
                        
                        // Implement Runnable. Don't extend Thread
                        // We're not making a specialized kind of Thread,
                        // just a taks to be run in a thread.
                        public class TERunner implements Runnable {
                          private final TE te;
                        
                          public TERunner(TE te) {
                            this.te = te;
                          }
                        
                          public void run() {
                            te.loadVec();
                          }
                        }
                        
                        public class Main {
                          public static void main(String[] args) {
                            TE te = new TE();
                            TERunner r1 = new TERunner(te);
                            TERunner r2 = new TERunner(te);
                            Thread t1 = new Thread(r1);
                            Thread t2 = new Trhead(r2);
                            t1.start();
                            t2.start();
                          }
                        }
                        This way, your TE class doesn't have to know anything about threading (other than that we've synced its load methods for demonstration purposes). It's only job is to load the Vector and ArrayList. The Runnable then has the job of calling the load methods on its TE. This is more fitting, as these are the tasks we want to perform in their own thread

                        I left the load method synced here so you could see how that will work--both threads are calling the sync method on the same TE object, so only one can execute it at a time. However, in a real-world situation, I would not declare that method synced. Instead, I'd probably do something like this in the Runner:
                          public void run() {
                            synchronized(te) {
                              te.loadVec();
                            }
                          }
                        This way it's the runner's job to know that other threads might be operating on the same TE, and so it is responsible for the syncing. The details of course would depend on the overall real situation.
                        • 9. Re: Confussion about synchronization
                          807580
                          Wow! Really, really thanks!

                          This example you give me is very nice to understand it clearly!

                          Thanks jverd.

                          Regards,