EI-01
EI-01

Reputation: 1095

Trouble understanding synchronized in java

Hello everyone i am doing a simple program that computes the sum of numbers from 0 to 99. I was reading on threads in java and I'm trying to understand how it works especially multithreading so i wrote a simple program to understand the concept. But the output from my program is different as it outputs 0 and 4950. It seems there are 2 threads running? The main thread and then object thread a? I have a problem from output cause they are not synchronized. I hope i am on the right track but am not sure and need guidance. Could someone please explain how to use the synchronized to solve this problem. Having trouble understanding it?

public class Testing {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        Thread a = new Thread(b);
        a.start();
        System.out.println(b.total);
    }
}    

class ThreadB extends Thread {
    int total;

    public ThreadB() {
        this.total = 0;
    }

    public synchronized int total() {
        for(int i = 0; i < 100; i++) {
            total += i;
        }
        return total;
    }

    public void run() {
        System.out.println(total());
    }
}

Upvotes: 2

Views: 119

Answers (3)

Nathan Hughes
Nathan Hughes

Reputation: 96444

Just to be clear, there are only two threads here. There is the thread provided by the JVM that is used to execute the main method. Then there is a local variable named a that references a Thread object. The local variable b refers to a Thread, but it isn't used as a thread because it never has start called on it. All Threads implement Runnable, passing b into the constructor of Thread a means that b is used as a Runnable by a. So the thread a runs, executing the run method defined in b.

When a executes b's run method, the lock on b is uncontended. Nothing else in the program is trying to acquire the lock on b. The synchronized keyword on total() only affects threads calling the total() method, so nothing is preventing the main method from accessing the instance member of b called total. So the main method goes ahead and accesses total, which hasn't been updated at this point, because thread a is still getting started.

If you made total private, and added an accessor to ThreadB like this:

public synchronized int getTotal() { return total;}

then calling this getter would force the caller to acquire the lock (because synchronized here means, "use the instance this method is called on as the lock", so the total() method and the new getTotal() method would share the same lock) before getting access to the total value. Then, once thread a enters its run method it would acquire the lock on b, and the main thread would have to wait until it could acquire the lock on b in order to access total.

Even if you do that, though, it's likely the main thread will still be able to access b and acquire the lock before thread a can get started and acquire the lock on b. There's a race condition between the main thread and thread a, and the main thread has the advantage because it's already started and active (while starting a new thread is expensive). You can add a Thread.sleep to the main method, before getting the total, so that the b thread gets a chance to acquire the lock first.

Upvotes: 0

Eric B.
Eric B.

Reputation: 24481

Synchronization is something required when two or more thread are trying to access the same resource and you want to ensure that they are not doing it at the same time. This is usually critical from a write perspective, but less so from a read (ie: multiple threads can read a value at the same time, just not at the same time as it is being updated, or not have multiple threads update the same resource at the same time).

In your example, you only really have 1 thread really running. I don't suspect that was the intention. There is the main thread and thread a. I have reorganized your code without changing anything but that will hopefully be more clear:

public class Testing {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        System.out.println(b.total);

        Thread a = new Thread(b);
        a.start();
    }
}    

The main thread doesn't actually do anything. It just creates a new object b, and prints out b.total (hence the 0 value you get). At the very least, you should be calling b.start() as well.

The computation thread you launch is done when you call a.start(). This part launches the computation in ThreadB() object which prints the computation total.

If you truly want to test out concurrency then you need to have a shared resource that multiple threads access. In your case, however, since total is a private instance member, both thread a and b will have different instances of total and not have any synchronization problems. The synchronized statement is superfluous since each thread is calling it's own total() method.

http://www.tutorialspoint.com/java/java_thread_synchronization.htm has a good explanation / example of synchronized and multi-threading.

Upvotes: 0

mattm
mattm

Reputation: 5949

You have two threads: the main thread, and thread 'a'. You have another object b, which inherits from Thread, but which you treat as an int.

You run thread a, which performs the summation, and prints the result. Then you print the value in stored b.

There is no issue in synchronization because none of your threads share the same variables. The int total is distinct between a and b. If you want to create an issue, make the int a member of Testing.

Upvotes: 1

Related Questions