user2514421
user2514421

Reputation: 37

Multi threading

I have an idea about multi-threading but I never worked on it. So, when I see my application at work... I haven't seen any class extending Thread creating a Thread. So, synchronized keyword is used when 2 objects try to access a variable at the same time.. we use synchronized to avoid conflicts.

Example:

public class Test {

    private static int count = 0;

    public static synchronized void incrementCount() {
        count++;
    }
} 

If test class was using by an object then it makes sense to add synchronized to incrementcount(). But when you don't extend Thread or Runnable then what's the use of writing synchronized.

Upvotes: 2

Views: 166

Answers (3)

Ravindra babu
Ravindra babu

Reputation: 38910

A class does not need to extend Thread or implements Runnable to mark it's method as synchronized to protect from multiple thread access

Your class may a parameter to some other thread class and that thread class may have multiple instances. To provide strong consistency of data, you have protect your critical section of code & data.

Just change your code example as below.

I am demonstrating "synchronized" at object level rather than class level ( static synchronized)

class Test {
    private int count = 0;
    public void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        Test t = new Test();
        for ( int i=0; i<10; i++){
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

Your class Test has been passed as a parameter to thread MyRunnable. Now you have created multiple instances of threads. In absence of synchronized keyword, the output is unpredictable as follows.

java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8

If I change

public void incrementCount() {

to

public synchronized void incrementCount() {

the output is:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

On a different note, you have make your method as static synchronized. That means lock is maintained at class level instead of object level.

Have a look at oracle documentation page for better understanding.

Demo of code for absence of "static synchronized"

class Test {
    private static int count = 0;
    public static void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        for ( int i=0; i<10; i++){
            Test t = new Test();
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

output:

Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6

After making

public static void incrementCount() {

to

ppublic static synchronized void incrementCount() {

output:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

In this example, unlike earlier, we have created 10 different Test instances.

Upvotes: 1

Nathan Hughes
Nathan Hughes

Reputation: 96385

Synchronized isn't for threads or Runnables, it's used for data structures that are accessed by multiple threads in order to make sure each thread accesses them in a way that doesn't corrupt their data. Your own example is a rudimentary case of this, where count is incremented in a way that isn't threadsafe (using ++, see this question), so it needs locking to make sure only one thread at a time can increment it.

If there's other code that accesses count it also needs to be synchronized so that updates to count are visible to it. If all you're doing is incrementing a counter then it makes more sense to use a class like java.util.concurrent.atomic.AtomicInteger, and you can do without the synchronized keyword altogether.

For using synchronized to make sense it does assume there are multiple threads. Even if your own code doesn't create new threads, there can be cases where multiple threads are calling your code (such as in a servlet container, where the container manages a threadpool and allocates a thread to each incoming request).

Upvotes: 2

AMACB
AMACB

Reputation: 1298

i++, even though it looks like a single instruction, is actually multiple instructions:

  1. Set a temporary variable to 1+i.
  2. Set the variable i to the temporary variable.

However, suppose the thread that executes i++ is interrupted after step 1, and the interrupting thread also calls i++. Then, this would happen:

(Suppose i=1)

  1. Original thread: set temporary variable1 to 1+i, or 2.
  2. Interrupting thread: set temporary variable2 to i+1, also 2
  3. Interrupting thread: set i to temporary variable2. Now i=2
  4. Original thread: set i to temporary variable1. Now i=2

The problem is that if i++ is called twice, it should be 3, not 2.


A synchronized void would put a lock on the variable i until the entire void completes executing. For example:

  1. Original thread: set temporary variable1 to 1+i, or 2. Puts a lock on the variable i.
  2. Interrupting thread: TRIES TO set temporary variable2 to i+1, but waits because of the lock on variable i
  3. Original thread: set i to temporary variable1. Now i=2. The variable i is now unlocked.
  4. Interrupting thread: "notices" that i has been unlocked, so it sets temporary variable2 to i+1 which is 3.
  5. Interrupting thread: sets i to 3, which is expected behavior.

synchronized voids essentially lock variables temporarily to avoid confusing the program's execution.

Upvotes: 0

Related Questions