Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java synchronized on method Not working?

I'm experimenting Java Multi-Threading using synchronization on method comparing with Atomic variables (java.util.concurrent.atomic package).

Below are the classes:

// Interface ICounter.java
        public interface ICounter {
            public void increment();
            public void decrement();
            public int value();
        }

// Class Counter.java
    public class Counter implements ICounter {
        private int c = 0;

        @Override
        public void increment() {
            c++;
        }

        @Override
        public void decrement() {
            c--;
        }

        @Override
        public int value() {
            return c;
        }
    }

// Class AtomicCounter.java
    import java.util.concurrent.atomic.AtomicInteger;

    public class AtomicCounter implements ICounter {
        private AtomicInteger c = new AtomicInteger(0);

        @Override
        public void increment() {
            c.incrementAndGet();
        }

        @Override
        public void decrement() {
            c.decrementAndGet();
        }

        @Override
        public int value() {
            return c.get();
        }

        public long getIncrement() {
            return c.incrementAndGet();
        }
    }

// Class MainProg.java
    public class MainProg {
        public static void main(String args[]) {
            ICounter counter = new AtomicCounter();
                    //ICounter counter = new SynchronizedCounter();
            Thread thread1 = new Thread(new CountRunner(counter));
            Thread thread2 = new Thread(new CountRunner(counter));

            thread1.start();
            thread2.start();
        }
    }

    class CountRunner implements Runnable {
        private ICounter counter;
        public CountRunner(ICounter counter) {
            this.counter = counter;
        }

        public void run() {
            while (true) {
                counter.increment();
                System.out.println(Thread.currentThread().getName() + " count=" + counter.value());
                System.out.println("-------------------");
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

The results from running either the Atomic or Synchronized do not show that the variable integer is thread-safe, e.g.:

Thread-0 count=1
-------------------
Thread-1 count=2
-------------------
Thread-0 count=3
-------------------
Thread-1 count=4
-------------------
Thread-0 count=5
-------------------
Thread-1 count=6
-------------------
Thread-0 count=7
-------------------
Thread-1 count=8
-------------------
Thread-0 count=10
-------------------
Thread-1 count=10
-------------------

From the results, the last 2 lines show the 2 threads were accessing the same value of integer variable of the counter class. Perhaps I am missing something here?

Thanks!

like image 454
itabashi Avatar asked Aug 15 '10 19:08

itabashi


People also ask

Can we synchronize method in Java?

Java Synchronized Method Synchronized method is used to lock an object for any shared resource. When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task.

Can I synchronize a static method in Java?

Static Synchronized method is also a method of synchronizing a method in java such that no two threads can act simultaneously static upon the synchronized method. The only difference is by using Static Synchronized. We are attaining a class-level lock such that only one thread will operate on the method.

Is lock required for synchronized method?

If a thread wants to execute a synchronized method on a given object, first it has to get a lock of that object. Once thread got the lock then it is allowed to execute any synchronized method on that object.

How does synchronize work in Java?

A synchronized block in Java is synchronized on some object. All synchronized blocks synchronize on the same object can only have one thread executing inside them at a time. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.


3 Answers

You're incrementing the value in one step, then getting the value in another step. While each of these individual steps is guaranteed to be atomic by the underling AtomicInteger class, the fact that you make two separate operations leaves the value you see in your print statement at the mercy of the order of execution of the threads.

To be able to accurately display the value updated by a given thread, you need to both update and get the resulting value in a single operation, which your getIncrement() method does. The code which would give you the expected results would look like this:

int changedValue = counter.getIncrement();
System.out.println(Thread.currentThread().getName() + " count=" + changedValue);
like image 147
Tim Stone Avatar answered Oct 06 '22 00:10

Tim Stone


because your counter.increment() and System.out.println is not one atomic action.

Thread 1               Thread2

increment

                       increment

                       System.out.println  // print 10

System.out.println  
// print 10 too
like image 25
irreputable Avatar answered Oct 05 '22 22:10

irreputable


What you missed is that your AtomicCounter class does work correctly, and the observed behaviour occurs becase the threads switched between the call to .increment() and .value():

-------------------
Thread-0 increment -> value = 9
-------------------
Thread-1 increment -> value = 10
-------------------
Thread-0 print value <- 10
-------------------
Thread-1 print value <- 10
-------------------
like image 32
rsp Avatar answered Oct 05 '22 22:10

rsp