• Post Reply Bookmark Topic Watch Topic
  • New Topic

Can't get synchronization to work  RSS feed

 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
I'm working through an exercise from a book:

Synchronizing a Block of Code
In this exercise we will attempt to synchronize a block of code. Within that block of code we will get the lock on an object, so that other threads cannot modify it while the block of code is executing. We will be creating three threads that will all attempt to manipulate the same object. Each thread will output a single letter 100 times, and then increment that letter by one. The object we will be using is StringBuffer. We could synchronize on a String object, but strings cannot be modified once they are created, so we would not be able to increment the letter without generating a new String object. The final output should have 100 As, 100 Bs, and 100 Cs all in unbroken lines.

1. Create a class and extend the Thread class.
2. Override the run() method of Thread. This is where the synchronized block of code will go.
3. For our three thread objects to share the same object, we will need to create a constructor that accepts a StringBuffer object in the argument.
4. The synchronized block of code will obtain a lock on the StringBuffer object from step 3.
5. Within the block, output the StringBuffer 100 times and then increment the letter in the StringBuffer. You can check Chapter 6 for StringBuffer methods that will help with this.
6. Finally, in the main() method, create a single StringBuffer object using the letter A, then create three instances of our class and start all three of them.


I can't get my code to work. I think it's because I've got 3 instances of a class and it seems you can't synchronize across instances of a class. But the exercise instructions don't mention any of that.
It's all a bit foggy but I guess the problem is, if I create a class that extends Thread, it must have a run() method; how do I get the run() method of a class to synchronize across 3 instances of the class? God this is so confusing.
My attempt at the problem is this (note I changed from 100 iterations to 10 for obvious reasons):



which creates the following output:

in main: main
18:46:49.909:0 - Thread03 - sb is: A
18:46:49.909:0 - Thread01 - sb is: A
18:46:49.909:0 - Thread02 - sb is: A
18:46:50.010:1 - Thread01 - sb is: A
18:46:50.010:1 - Thread03 - sb is: A
18:46:50.014:1 - Thread02 - sb is: A
18:46:50.111:2 - Thread01 - sb is: A
18:46:50.115:2 - Thread03 - sb is: A
18:46:50.116:2 - Thread02 - sb is: A
18:46:50.212:3 - Thread01 - sb is: A
18:46:50.216:3 - Thread03 - sb is: A
18:46:50.217:3 - Thread02 - sb is: A
18:46:50.313:4 - Thread01 - sb is: A
18:46:50.316:4 - Thread03 - sb is: A
18:46:50.318:4 - Thread02 - sb is: A
18:46:50.414:5 - Thread01 - sb is: A
18:46:50.417:5 - Thread03 - sb is: A
18:46:50.419:5 - Thread02 - sb is: A
18:46:50.515:6 - Thread01 - sb is: A
18:46:50.518:6 - Thread03 - sb is: A
18:46:50.520:6 - Thread02 - sb is: A
18:46:50.616:7 - Thread01 - sb is: A
18:46:50.619:7 - Thread03 - sb is: A
18:46:50.621:7 - Thread02 - sb is: A
18:46:50.717:8 - Thread01 - sb is: A
18:46:50.719:8 - Thread03 - sb is: A
18:46:50.721:8 - Thread02 - sb is: A
18:46:50.818:9 - Thread01 - sb is: A
18:46:50.820:9 - Thread03 - sb is: A
18:46:50.823:9 - Thread02 - sb is: A
18:46:50.919: - Thread01 - sb: Changing sb(0) from A to B
18:46:50.921: - Thread03 - sb: Changing sb(0) from B to C
18:46:50.924: - Thread02 - sb: Changing sb(0) from C to D


This isn't I think what is expected. I think Thread01 is supposed to run 10 times, then increments sb to B, then Thread02 runs 10 times, then increments sb to C then Thread03 runs 10 times incrementing sb to D.
By the way, the only reason it looks "neat" is because I have the sleep(100) in there; if I change that to sleep(0) I get this:

in main: main
18:47:58.546:0 - Thread03 - sb is: A
18:47:58.546:0 - Thread01 - sb is: A
18:47:58.546:0 - Thread02 - sb is: A
18:47:58.549:1 - Thread01 - sb is: A
18:47:58.548:1 - Thread03 - sb is: A
18:47:58.557:2 - Thread01 - sb is: A
18:47:58.553:1 - Thread02 - sb is: A
18:47:58.566:3 - Thread01 - sb is: A
18:47:58.562:2 - Thread03 - sb is: A
18:47:58.575:4 - Thread01 - sb is: A
18:47:58.571:2 - Thread02 - sb is: A
18:47:58.584:5 - Thread01 - sb is: A
18:47:58.579:3 - Thread03 - sb is: A
18:47:58.593:6 - Thread01 - sb is: A
18:47:58.588:3 - Thread02 - sb is: A
18:47:58.602:7 - Thread01 - sb is: A
18:47:58.597:4 - Thread03 - sb is: A
18:47:58.610:8 - Thread01 - sb is: A
18:47:58.606:4 - Thread02 - sb is: A
18:47:58.624:9 - Thread01 - sb is: A
18:47:58.615:5 - Thread03 - sb is: A
18:47:58.628: - Thread01 - sb: Changing sb(0) from A to B
18:47:58.625:5 - Thread02 - sb is: A
18:47:58.633:6 - Thread03 - sb is: A
18:47:58.642:6 - Thread02 - sb is: B
18:47:58.646:7 - Thread03 - sb is: B
18:47:58.650:7 - Thread02 - sb is: B
18:47:58.655:8 - Thread03 - sb is: B
18:47:58.659:8 - Thread02 - sb is: B
18:47:58.664:9 - Thread03 - sb is: B
18:47:58.668:9 - Thread02 - sb is: B
18:47:58.673: - Thread03 - sb: Changing sb(0) from B to C
18:47:58.677: - Thread02 - sb: Changing sb(0) from B to C


Thanks in advance for any help here.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steven Squeers wrote:
1. Create a class and extend the Thread class.
2. Override the run() method of Thread. This is where the synchronized block of code will go.
3. For our three thread objects to share the same object, we will need to create a constructor that accepts a StringBuffer object in the argument.
4. The synchronized block of code will obtain a lock on the StringBuffer object from step 3.
5. Within the block, output the StringBuffer 100 times and then increment the letter in the StringBuffer. You can check Chapter 6 for StringBuffer methods that will help with this.
6. Finally, in the main() method, create a single StringBuffer object using the letter A, then create three instances of our class and start all three of them.


I can't get my code to work. I think it's because I've got 3 instances of a class and it seems you can't synchronize across instances of a class. ...



To synchronize multiple threads you need to synchronize on the SAME object. Step 4. of the instructions tell you to use a synchronized block to get the lock for the StringBuffer object. Your code uses a synchronized method. So it doesn't follow the instructions from the book. Hopefully the book shows you how to create a synchronized block using an arbitrary object to get the lock.
 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Steve. I noticed that but it doesn't help, because although yes if I code a synchronized block I can synchronize on any instance of an Object (at least as far as I know), I'm still stuck because the instructions say

For our three thread objects to share the same object, we will need to create a constructor that accepts a StringBuffer object in the argument.

which I understand as saying: "your class that extends Thread should have an instance variable that is a StringBuffer and should have a constructor that takes a StringBuffer".
I don't understand how I can get this to work by having 3 instances of a class that extends Thread and which has a constructor that takes a StringBuffer object and then being able to synchronize on that object.
By the way, this is about all the book has on synchronized blocks:

synchronized(this) {
System.out.println("synchronized");
}


 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay, I've been able to get this to work by wrapping the code in f() inside a synchronized block, and synchronizing on C2.class (I just thought I'd give it a go and it worked):



giving the following output, which I think is correct:

in main: main
19:37:21.110:0 - Thread01 - sb is: A
19:37:21.112:1 - Thread01 - sb is: A
19:37:21.113:2 - Thread01 - sb is: A
19:37:21.116:3 - Thread01 - sb is: A
19:37:21.121:4 - Thread01 - sb is: A
19:37:21.125:5 - Thread01 - sb is: A
19:37:21.130:6 - Thread01 - sb is: A
19:37:21.134:7 - Thread01 - sb is: A
19:37:21.139:8 - Thread01 - sb is: A
19:37:21.143:9 - Thread01 - sb is: A
19:37:21.147: - Thread01 - sb: Changing sb(0) from A to B
19:37:21.152:0 - Thread03 - sb is: B
19:37:21.156:1 - Thread03 - sb is: B
19:37:21.161:2 - Thread03 - sb is: B
19:37:21.165:3 - Thread03 - sb is: B
19:37:21.170:4 - Thread03 - sb is: B
19:37:21.179:5 - Thread03 - sb is: B
19:37:21.180:6 - Thread03 - sb is: B
19:37:21.183:7 - Thread03 - sb is: B
19:37:21.187:8 - Thread03 - sb is: B
19:37:21.192:9 - Thread03 - sb is: B
19:37:21.196: - Thread03 - sb: Changing sb(0) from B to C
19:37:21.201:0 - Thread02 - sb is: C
19:37:21.205:1 - Thread02 - sb is: C
19:37:21.210:2 - Thread02 - sb is: C
19:37:21.214:3 - Thread02 - sb is: C
19:37:21.218:4 - Thread02 - sb is: C
19:37:21.223:5 - Thread02 - sb is: C
19:37:21.227:6 - Thread02 - sb is: C
19:37:21.232:7 - Thread02 - sb is: C
19:37:21.236:8 - Thread02 - sb is: C
19:37:21.241:9 - Thread02 - sb is: C
19:37:21.245: - Thread02 - sb: Changing sb(0) from C to D

My question is: is this the right way to do it? It feels a bit "hacky". Am I not supposed to synchronize on the actual object - the StringBuffer instance shared by all 3 instances of my Thread class - that is being "mutated" i.e. changed? Or does it not matter what you use to lock/synchronize on?

Thanks.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steven Squeers wrote:My question is: is this the right way to do it? It feels a bit "hacky". Am I not supposed to synchronize on the actual object - the StringBuffer instance shared by all 3 instances of my Thread class - that is being "mutated" i.e. changed?

No, you are not doing it right - that would be akin to a static lock (locking a static method). It could have unexpected side effects in real-world situations (too general a lock could lead to too-much blocking and serious degradation in performance).

But yes, the correct way is what you suggest (and what the book's instructions specifically tell you): synchronize using the StringBuffer instance that you shared with all 3 threads. You may have three variables, but you have just one Object, and your synchronization locks are retrieved from Objects, not variables. So they would all use the same lock. It is good practice to lock on the data you are protecting (in this case the StringBuffer) because it helps ensure the locks are as narrow as possible. There are exceptions but the principle is sound for simple locking.
 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steve Luke wrote: the correct way is what you suggest (and what the book's instructions specifically tell you): synchronize using the StringBuffer instance that you shared with all 3 threads. You may have three variables, but you have just one Object, and your synchronization locks are retrieved from Objects, not variables. So they would all use the same lock. It is good practice to lock on the data you are protecting (in this case the StringBuffer) because it helps ensure the locks are as narrow as possible. There are exceptions but the principle is sound for simple locking.


Eh, that's weird. I was just in the middle of writing "yes but I tried this - synchronizing on this.sb - before and it didn't work" when I tried it again and it works. I must have been doing something else wrong somewhere earlier.
I've changed this line



to



and it works.
So presumably that's the right way to do it, yes (hoping..hoping)?

Thanks.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steven Squeers wrote:So presumably that's the right way to do it, yes (hoping..hoping)?

Yup, that is correct
 
Steven Squeers
Ranch Hand
Posts: 62
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Great, many thanks Steve for your quick and valuable help today
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!