Reputation: 37
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
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
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
Reputation: 1298
i++
, even though it looks like a single instruction, is actually multiple instructions:
1+i
.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+i
, or 2
. i+1
, also 2
i
to temporary variable2. Now i=2
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+i
, or 2
. Puts a lock on the variable i
.i+1
, but waits because of the lock on variable i
i
to temporary variable1. Now i=2
. The variable i
is now unlocked.i
has been unlocked, so it sets temporary variable2 to i+1
which is 3
.i
to 3
, which is expected behavior.synchronized void
s essentially lock variables temporarily to avoid confusing the program's execution.
Upvotes: 0