0

i' m studying multithreading, and i'm little bit confused about few things,

for example

public class Example{ public void function1(){ int toPrint = 0; System.out.println(toPrint); for(int i = 0; i < 10; i++) System.out.println("hello stackOverflow!"); } public syncrhonized void function2(){ ... } } public static void main(String[] args) { Example example = new Example(); for (int i = 0; i < 10; i++) { RunningThread thread = new RunningThread(example); thread.start(); } } 

and a loop like this

public class RunningThread{ Example instanceClass; public RunningThread(Example instanceClass){ this.instanceClass = instanceClass; public void run(){ while(true){ instanceClass.function1(); instanceClass.function2(); } } 

Now i can't show images, but i want to be clear on my dubts so

if i start N threads, i have to intend this situation

 _______________________________ ______________________________ | thread1 | | thread..N | ................................. ................................ | function1 | | function1 | | int toPrint = 0; | | int toPrint = 0; | | System.out.println(toPrint); | | System.out.println(toPrint);| | for(int i = 0; i < 10; i++) | | for(int i = 0; i < 10; i++) | | System.out.println(); | | System.out.println(); | --------------------------------- -------------------------------- 

what i means is that, each threads has his own flow ( his own "copy" of function1) ,and after finishing they will wait to execute the locked function2()?

or

 _______________________________ | thread1 and thread..N | ................................. | function1 | | int toPrint = 0; | | System.out.println(toPrint); | | for(int i = 0; i < 10; i++) | | System.out.println(); | --------------------------------- 

in this way each thread shares the same function and contents ( so for example one thread initialize the value and another thread not initialize it) and after finishing they will wait to execute the locked function2()?

the execution order will be always respected, first function1 and the function2 ?

excuse me if this is so long, anyway thanks in advance.

5
  • I don't see any threads in your code. Further, I don't see multiple threads calling function2. Commented Nov 3, 2014 at 13:12
  • Please show us the complete code. Commented Nov 3, 2014 at 13:13
  • wait , i'll insert when i start the thread, but i think this is secondary... Commented Nov 3, 2014 at 13:14
  • 1
    Each thread has its own local variables. Synchronization is used to protect shared state. Commented Nov 3, 2014 at 13:14
  • @ElliottFrisch code Updated Commented Nov 3, 2014 at 13:17

2 Answers 2

4

The synchronized keyword does not lock the function, but the object, meaning that two threads cannot use the same object concurrently. synchronized void function2 is just syntactic sugar for

void function2(){synchronized(this){// 

The reason to synchronize, i.e., lock objects is that no thread can see an object in a state where its invariant is broken. In your example, the class Example has no state, and hence no invariant, meaning that you do not need to lock it.

What you seem to be concerned about are the local variables of function2. However, local variables are never shared between threads, so each thread will have its own instance of each local variable.


Addendum: As suggested by user hexafraction, an example where synchronization is required:

Consider the following simple class:

public class Example { public int count = 0; public void increment() { count++; } public void decrement() { count--; } } 

This class is mutable; its state is defined by the value of count. If a client calls either increment or decrement, then the state is supposed to change. Both methods have a contract to adhere to:

  • increment must guarantee that the value of count is the old value of count plus one. Let's denote this contract by count = old(count) + 1

  • Simliarly, the contract of decrement is count = old(count) - 1

Let's run this class sequentally:

public static void main(String[] args) { Example sharedData = new Example(); for (int i = 0; i < 1000; i++) sharedData.increment(); System.out.println("Incrementer finished"); for (int i = 0; i < 1000; i++) sharedData.decrement(); System.out.println("Decrementer finished"); System.out.println(sharedData.count); } 

It prints:

Incrementer finished Decrementer finished 0 

We can run the code as much as we want, the result will always be the same.

Let us define multiple threads that use the same instance of the class Example concurrently:

public static void main(String[] args) throws InterruptedException { Example sharedData = new Example(); Thread incrementer = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) sharedData.increment(); System.out.println("Incrementer finished"); } }); Thread decrementer = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) sharedData.decrement(); System.out.println("Decrementer finished"); } }); incrementer.start(); decrementer.start(); incrementer.join(); decrementer.join(); System.out.println(sharedData.count); } 

We now have two threads: An incrementer and a decrementer. The code looks a bit different, but we might expect it to reach the same result. Again, we call increment and decrement both 1000 times on our shared sharedData. But now, the result is completely nondeterministic. Running the code multiple times, the numbers that are printed may be: 16, -76, 138, -4.

How can this be? We are always either adding one or subracting one, but after doing both 1000 times, we ought to have the value 0, right? The problem is that one thread may be ignorant to changes of the other thread. Note that count++ does not happen atomic; it is the same as count = count + 1, which consists of a read, a computation and a write.

Consider the following sequential history:

incrementer enters increment and reads the value of count, count == 0 decrementer enters decrement and reads the value of count, count == 0 incrementer adds one and modifies the state, count == 1 decrementer subtracts one and modifies the state, count == -1 

Note that the state change computed by decrementer is based on the value of count that it read, i.e., 0, which means that it did not see the state changes done by the incrementer.

There are multiple ways to solve this problem, but let us try the synchronized keyword. We can disallow concurrent modifications of the shared instance of Example by locking the instance. So lets modify our class:

public class Example { public int count = 0; public synchronized void increment() { count++; } public synchronized void decrement() { count--; } } 

It is important to have both methods lock the instance, because both methods must not see the object in an inconsistent state.

What if we could not modify the code of Example, e.g., because it is part of a library we use? How could we employ the synchronized keyword to use the code by multiple threads? As already mentioned, synchronized void increment(){ is the same as void increment(){synchronized(this), so synchronization is not an attribute of the method, but the object. Leaving the code of Example unchanged, we could have changed our client instead:

public static void main(String[] args) throws InterruptedException { Example sharedData = new Example(); Thread incrementer = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) synchronized (sharedData){ sharedData.increment(); } System.out.println("Incrementer finished"); } }); Thread decrementer = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) synchronized (sharedData){ sharedData.decrement(); } System.out.println("Decrementer finished"); } }); incrementer.start(); decrementer.start(); incrementer.join(); decrementer.join(); System.out.println(sharedData.count); } 
Sign up to request clarification or add additional context in comments.

2 Comments

You should add an example in which multiple methods have the synchronized keyword.
@hexafraction Thank you for the feedback. I kept the original answer on top, but added an example (and explanation) with two methods where synchronization is important.
0

Since you made both function1 and function2 synchronized no thread can leave them before execution is over, so there is no way one thread is stopped in the middle of function1 and another thread executes its function1 or function2. But do note that if the same run() method is there in both threads (which is what I guess), while the first has finished function1 the dispatcher or scheduler may stop it and run thread2, which can complete both function calls, and then thread1 may continue.

NOTE: Use methods() rather that functions().

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.