This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Understanding how synchronized works / possible bug?

8 replies
snim2
Joined: 2012-02-06,
User offline. Last seen 42 years 45 weeks ago.

Hi there,

I'm trying to understand how "synchronized" can be used correctly in
Scala to implement a critical section. A colleague and I have
implemented some simple / contrived examples that use synchronized,
these examples all create an array of 256 Ints, and have two threads
iterating over the whole array 100,000 times, updating each array
element by adding one to the value. So, once each thread has finished
running, every element in the array should be 100000. I've put the
examples in a gist here: https://gist.github.com/1751700

We've tried various ways to create the critical section with different
levels of success (example output here is from scala 2.8.1.final on
Ubuntu Oneiric) and we're trying to understand why each version works
or doesn't:

1) Call synchronized as a method of the array, seems to work fine, as
you would expect from the doc's:

bins.synchronized {
bins(j) += 1
}

2) Call synchronized as a method of "this" object, where "this"
extends Runnable. This doesn't work, some array elements do not get
updated:

this.synchronized {
bins(j) += 1
}

Full code listing for this example is here:
https://gist.github.com/1751700#file_sync_example.scala
Typical output: Bins are NOT valid. 789 iterations missing.

3) Create a new synchronized method and call that, again doesn't seem
to work and some elements are not updated:

def update(index: Int) : Unit = synchronized {
bins(index) += 1
}
...
for ...
update(j)

Full code listing for this example is here:
https://gist.github.com/1751700#file_sync_example.scala
Typical output: Bins are NOT valid. 111560 iterations missing.

4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
of an Array. Use the "update" method which is synchronized in the
SynchronizedBuffer trait:

val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
...
bins.update(j, bins(j) + 1)

Full code listing for this example is here:
https://gist.github.com/1751700#file_sync_buffer_example.scala
Typical output: Bins are NOT valid. 641875 iterations missing.

So, why does synchronized not work when called as a method of "this"?
Should it never be used in this fashion?

Why does 3) not work? I notice that adding a println() statement
inside that update() method seems to work, is this a (heisen)bug in my
code?

Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
update() method I'm calling there actually the synchronized one from
the trait?

Many thanks in advance for your advice,

Sarah

Viktor Klang
Joined: 2008-12-17,
User offline. Last seen 1 year 27 weeks ago.
Re: Understanding how synchronized works / possible bug?
Hi Sarah,
Using synchronized is not ideal, for many reasons.Look into: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicIntegerArray.html
Cheers,√

On Mon, Feb 6, 2012 at 1:20 PM, snim2 <mount [dot] sarah [at] gmail [dot] com> wrote:
Hi there,

I'm trying to understand how "synchronized" can be used correctly in
Scala to implement a critical section. A colleague and I have
implemented some simple / contrived examples that use synchronized,
these examples all create an array of 256 Ints, and have two threads
iterating over the whole array 100,000 times, updating each array
element by adding one to the value. So, once each thread has finished
running, every element in the array should be 100000.  I've put the
examples in a gist here: https://gist.github.com/1751700

We've tried various ways to create the critical section with different
levels of success (example output here is from scala 2.8.1.final on
Ubuntu Oneiric) and we're trying to understand why each version works
or doesn't:


1) Call synchronized as a method of the array, seems to work fine, as
you would expect from the doc's:

bins.synchronized {
   bins(j) += 1
}


2) Call synchronized as a method of "this" object, where "this"
extends Runnable. This doesn't work, some array elements do not get
updated:

this.synchronized {
   bins(j) += 1
}

Full code listing for this example is here:
https://gist.github.com/1751700#file_sync_example.scala
Typical output: Bins are NOT valid. 789 iterations missing.


3) Create a new synchronized method and call that, again doesn't seem
to work and some elements are not updated:

def update(index: Int) : Unit = synchronized {
       bins(index) += 1
}
...
for ...
   update(j)


Full code listing for this example is here:
https://gist.github.com/1751700#file_sync_example.scala
Typical output: Bins are NOT valid. 111560 iterations missing.


4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
of an Array. Use the "update" method which is synchronized in the
SynchronizedBuffer trait:

val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
...
bins.update(j, bins(j) + 1)

Full code listing for this example is here:
https://gist.github.com/1751700#file_sync_buffer_example.scala
Typical output: Bins are NOT valid. 641875 iterations missing.


So, why does synchronized not work when called as a method of "this"?
Should it never be used in this fashion?

Why does 3) not work? I notice that adding a println() statement
inside that update() method seems to work, is this a (heisen)bug in my
code?

Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
update() method I'm calling there actually the synchronized one from
the trait?


Many thanks in advance for your advice,

Sarah



--
Viktor Klang

Akka Tech LeadTypesafe - The software stack for applications that scale

Twitter: @viktorklang
snim2
Joined: 2012-02-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Understanding how synchronized works / possible bug?

Thanks √iktor, I'm aware that using synchronized is not necessarily a
good idea, I'm not trying to find a good solution to an engineering
problem here, I'm really just trying to understand how synchronized
does and doesn't work. AtomicIntegerArray looks very interesting, and
would probably be useful in a "real" situation, but it doesn't help me
understand synchronized :)

Cheers,

Sarah

2012/2/6 √iktor Ҡlang :
> Hi Sarah,
>
> Using synchronized is not ideal, for many reasons.
> Look
> into: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicIntegerArray.html
>
> Cheers,
> √
>
>
> On Mon, Feb 6, 2012 at 1:20 PM, snim2 wrote:
>>
>> Hi there,
>>
>> I'm trying to understand how "synchronized" can be used correctly in
>> Scala to implement a critical section. A colleague and I have
>> implemented some simple / contrived examples that use synchronized,
>> these examples all create an array of 256 Ints, and have two threads
>> iterating over the whole array 100,000 times, updating each array
>> element by adding one to the value. So, once each thread has finished
>> running, every element in the array should be 100000.  I've put the
>> examples in a gist here: https://gist.github.com/1751700
>>
>> We've tried various ways to create the critical section with different
>> levels of success (example output here is from scala 2.8.1.final on
>> Ubuntu Oneiric) and we're trying to understand why each version works
>> or doesn't:
>>
>>
>> 1) Call synchronized as a method of the array, seems to work fine, as
>> you would expect from the doc's:
>>
>> bins.synchronized {
>>    bins(j) += 1
>> }
>>
>>
>> 2) Call synchronized as a method of "this" object, where "this"
>> extends Runnable. This doesn't work, some array elements do not get
>> updated:
>>
>> this.synchronized {
>>    bins(j) += 1
>> }
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 789 iterations missing.
>>
>>
>> 3) Create a new synchronized method and call that, again doesn't seem
>> to work and some elements are not updated:
>>
>> def update(index: Int) : Unit = synchronized {
>>        bins(index) += 1
>> }
>> ...
>> for ...
>>    update(j)
>>
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 111560 iterations missing.
>>
>>
>> 4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
>> of an Array. Use the "update" method which is synchronized in the
>> SynchronizedBuffer trait:
>>
>> val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
>> ...
>> bins.update(j, bins(j) + 1)
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_buffer_example.scala
>> Typical output: Bins are NOT valid. 641875 iterations missing.
>>
>>
>> So, why does synchronized not work when called as a method of "this"?
>> Should it never be used in this fashion?
>>
>> Why does 3) not work? I notice that adding a println() statement
>> inside that update() method seems to work, is this a (heisen)bug in my
>> code?
>>
>> Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
>> update() method I'm calling there actually the synchronized one from
>> the trait?
>>
>>
>> Many thanks in advance for your advice,
>>
>> Sarah
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>

Kevin Wright 2
Joined: 2010-05-30,
User offline. Last seen 26 weeks 4 days ago.
Re: Understanding how synchronized works / possible bug?
I'm curious what your use-case is for looking into `synchronised` at all.  It's a very low-level interface and fraught with dragons (as you've seen).
Unless you have a specific concern over legacy code that uses synchronised (perhaps auto-converted from Java?), you'll find that Atomic/Concurrent primitives, Actors, Agents and Futures should meet all your needs.
Plus, they're also a whole lot more fun :)

2012/2/6 Sarah Mount <mount [dot] sarah [at] gmail [dot] com>
Thanks √iktor, I'm aware that using synchronized is not necessarily a
good idea, I'm not trying to find a good solution to an engineering
problem here, I'm really just trying to understand how synchronized
does and doesn't work. AtomicIntegerArray looks very interesting, and
would probably be useful in a "real" situation, but it doesn't help me
understand synchronized :)

Cheers,

Sarah

2012/2/6 √iktor Ҡlang <viktor [dot] klang [at] gmail [dot] com>:
> Hi Sarah,
>
> Using synchronized is not ideal, for many reasons.
> Look
> into: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicIntegerArray.html
>
> Cheers,
> √
>
>
> On Mon, Feb 6, 2012 at 1:20 PM, snim2 <mount [dot] sarah [at] gmail [dot] com> wrote:
>>
>> Hi there,
>>
>> I'm trying to understand how "synchronized" can be used correctly in
>> Scala to implement a critical section. A colleague and I have
>> implemented some simple / contrived examples that use synchronized,
>> these examples all create an array of 256 Ints, and have two threads
>> iterating over the whole array 100,000 times, updating each array
>> element by adding one to the value. So, once each thread has finished
>> running, every element in the array should be 100000.  I've put the
>> examples in a gist here: https://gist.github.com/1751700
>>
>> We've tried various ways to create the critical section with different
>> levels of success (example output here is from scala 2.8.1.final on
>> Ubuntu Oneiric) and we're trying to understand why each version works
>> or doesn't:
>>
>>
>> 1) Call synchronized as a method of the array, seems to work fine, as
>> you would expect from the doc's:
>>
>> bins.synchronized {
>>    bins(j) += 1
>> }
>>
>>
>> 2) Call synchronized as a method of "this" object, where "this"
>> extends Runnable. This doesn't work, some array elements do not get
>> updated:
>>
>> this.synchronized {
>>    bins(j) += 1
>> }
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 789 iterations missing.
>>
>>
>> 3) Create a new synchronized method and call that, again doesn't seem
>> to work and some elements are not updated:
>>
>> def update(index: Int) : Unit = synchronized {
>>        bins(index) += 1
>> }
>> ...
>> for ...
>>    update(j)
>>
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 111560 iterations missing.
>>
>>
>> 4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
>> of an Array. Use the "update" method which is synchronized in the
>> SynchronizedBuffer trait:
>>
>> val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
>> ...
>> bins.update(j, bins(j) + 1)
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_buffer_example.scala
>> Typical output: Bins are NOT valid. 641875 iterations missing.
>>
>>
>> So, why does synchronized not work when called as a method of "this"?
>> Should it never be used in this fashion?
>>
>> Why does 3) not work? I notice that adding a println() statement
>> inside that update() method seems to work, is this a (heisen)bug in my
>> code?
>>
>> Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
>> update() method I'm calling there actually the synchronized one from
>> the trait?
>>
>>
>> Many thanks in advance for your advice,
>>
>> Sarah
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>


Viktor Klang
Joined: 2008-12-17,
User offline. Last seen 1 year 27 weeks ago.
Re: Understanding how synchronized works / possible bug?


2012/2/6 Sarah Mount <mount [dot] sarah [at] gmail [dot] com>
Thanks √iktor, I'm aware that using synchronized is not necessarily a
good idea, I'm not trying to find a good solution to an engineering
problem here, I'm really just trying to understand how synchronized
does and doesn't work. AtomicIntegerArray looks very interesting, and
would probably be useful in a "real" situation, but it doesn't help me
understand synchronized :)

syncrhonized is merely a pimped method that essentially translates:
ref.synchronized { ... }
into
synchronized(ref) {
}
For more elaborate description I'd recommend http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601 There are plenty books on the topic.
My personal view is that it should always be avoided, if possible. Only very few problems need to be structured so that contending threads are parked.
Cheers,√ 

Cheers,

Sarah

2012/2/6 √iktor Ҡlang <viktor [dot] klang [at] gmail [dot] com>:
> Hi Sarah,
>
> Using synchronized is not ideal, for many reasons.
> Look
> into: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicIntegerArray.html
>
> Cheers,
> √
>
>
> On Mon, Feb 6, 2012 at 1:20 PM, snim2 <mount [dot] sarah [at] gmail [dot] com> wrote:
>>
>> Hi there,
>>
>> I'm trying to understand how "synchronized" can be used correctly in
>> Scala to implement a critical section. A colleague and I have
>> implemented some simple / contrived examples that use synchronized,
>> these examples all create an array of 256 Ints, and have two threads
>> iterating over the whole array 100,000 times, updating each array
>> element by adding one to the value. So, once each thread has finished
>> running, every element in the array should be 100000.  I've put the
>> examples in a gist here: https://gist.github.com/1751700
>>
>> We've tried various ways to create the critical section with different
>> levels of success (example output here is from scala 2.8.1.final on
>> Ubuntu Oneiric) and we're trying to understand why each version works
>> or doesn't:
>>
>>
>> 1) Call synchronized as a method of the array, seems to work fine, as
>> you would expect from the doc's:
>>
>> bins.synchronized {
>>    bins(j) += 1
>> }
>>
>>
>> 2) Call synchronized as a method of "this" object, where "this"
>> extends Runnable. This doesn't work, some array elements do not get
>> updated:
>>
>> this.synchronized {
>>    bins(j) += 1
>> }
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 789 iterations missing.
>>
>>
>> 3) Create a new synchronized method and call that, again doesn't seem
>> to work and some elements are not updated:
>>
>> def update(index: Int) : Unit = synchronized {
>>        bins(index) += 1
>> }
>> ...
>> for ...
>>    update(j)
>>
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 111560 iterations missing.
>>
>>
>> 4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
>> of an Array. Use the "update" method which is synchronized in the
>> SynchronizedBuffer trait:
>>
>> val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
>> ...
>> bins.update(j, bins(j) + 1)
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_buffer_example.scala
>> Typical output: Bins are NOT valid. 641875 iterations missing.
>>
>>
>> So, why does synchronized not work when called as a method of "this"?
>> Should it never be used in this fashion?
>>
>> Why does 3) not work? I notice that adding a println() statement
>> inside that update() method seems to work, is this a (heisen)bug in my
>> code?
>>
>> Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
>> update() method I'm calling there actually the synchronized one from
>> the trait?
>>
>>
>> Many thanks in advance for your advice,
>>
>> Sarah
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>



--
Sarah Mount, Senior Lecturer, University of Wolverhampton
website:  http://www.snim2.org/
twitter: @snim2



--
Viktor Klang

Akka Tech LeadTypesafe - The software stack for applications that scale

Twitter: @viktorklang
snim2
Joined: 2012-02-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Understanding how synchronized works / possible bug?

I'm aware of all the things you speak of, I almost put at the end of
my first email "please don't say 'use actors'"!

My "use case" isn't to solve an engineering problem. What we're trying
to do is build a comparative bunch of examples of various concurrency
abstractions for a class we're teaching with the conclusion that the
higher-level the abstraction the easier it is to get the concurrency
right. Hence, even though one might not choose to use synchronize in
practice, it would be useful to have a better understanding of how it
works.

Cheers,

Sarah

On Mon, Feb 6, 2012 at 13:28, Kevin Wright wrote:
> I'm curious what your use-case is for looking into `synchronised` at all.
>  It's a very low-level interface and fraught with dragons (as you've seen).
>
> Unless you have a specific concern over legacy code that uses synchronised
> (perhaps auto-converted from Java?), you'll find that Atomic/Concurrent
> primitives, Actors, Agents and Futures should meet all your needs.
>
> Plus, they're also a whole lot more fun :)
>
>
> 2012/2/6 Sarah Mount
>>
>> Thanks √iktor, I'm aware that using synchronized is not necessarily a
>> good idea, I'm not trying to find a good solution to an engineering
>> problem here, I'm really just trying to understand how synchronized
>> does and doesn't work. AtomicIntegerArray looks very interesting, and
>> would probably be useful in a "real" situation, but it doesn't help me
>> understand synchronized :)
>>
>> Cheers,
>>
>> Sarah
>>
>> 2012/2/6 √iktor Ҡlang :
>> > Hi Sarah,
>> >
>> > Using synchronized is not ideal, for many reasons.
>> > Look
>> >
>> > into: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicIntegerArray.html
>> >
>> > Cheers,
>> > √
>> >
>> >
>> > On Mon, Feb 6, 2012 at 1:20 PM, snim2 wrote:
>> >>
>> >> Hi there,
>> >>
>> >> I'm trying to understand how "synchronized" can be used correctly in
>> >> Scala to implement a critical section. A colleague and I have
>> >> implemented some simple / contrived examples that use synchronized,
>> >> these examples all create an array of 256 Ints, and have two threads
>> >> iterating over the whole array 100,000 times, updating each array
>> >> element by adding one to the value. So, once each thread has finished
>> >> running, every element in the array should be 100000.  I've put the
>> >> examples in a gist here: https://gist.github.com/1751700
>> >>
>> >> We've tried various ways to create the critical section with different
>> >> levels of success (example output here is from scala 2.8.1.final on
>> >> Ubuntu Oneiric) and we're trying to understand why each version works
>> >> or doesn't:
>> >>
>> >>
>> >> 1) Call synchronized as a method of the array, seems to work fine, as
>> >> you would expect from the doc's:
>> >>
>> >> bins.synchronized {
>> >>    bins(j) += 1
>> >> }
>> >>
>> >>
>> >> 2) Call synchronized as a method of "this" object, where "this"
>> >> extends Runnable. This doesn't work, some array elements do not get
>> >> updated:
>> >>
>> >> this.synchronized {
>> >>    bins(j) += 1
>> >> }
>> >>
>> >> Full code listing for this example is here:
>> >> https://gist.github.com/1751700#file_sync_example.scala
>> >> Typical output: Bins are NOT valid. 789 iterations missing.
>> >>
>> >>
>> >> 3) Create a new synchronized method and call that, again doesn't seem
>> >> to work and some elements are not updated:
>> >>
>> >> def update(index: Int) : Unit = synchronized {
>> >>        bins(index) += 1
>> >> }
>> >> ...
>> >> for ...
>> >>    update(j)
>> >>
>> >>
>> >> Full code listing for this example is here:
>> >> https://gist.github.com/1751700#file_sync_example.scala
>> >> Typical output: Bins are NOT valid. 111560 iterations missing.
>> >>
>> >>
>> >> 4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
>> >> of an Array. Use the "update" method which is synchronized in the
>> >> SynchronizedBuffer trait:
>> >>
>> >> val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
>> >> ...
>> >> bins.update(j, bins(j) + 1)
>> >>
>> >> Full code listing for this example is here:
>> >> https://gist.github.com/1751700#file_sync_buffer_example.scala
>> >> Typical output: Bins are NOT valid. 641875 iterations missing.
>> >>
>> >>
>> >> So, why does synchronized not work when called as a method of "this"?
>> >> Should it never be used in this fashion?
>> >>
>> >> Why does 3) not work? I notice that adding a println() statement
>> >> inside that update() method seems to work, is this a (heisen)bug in my
>> >> code?
>> >>
>> >> Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
>> >> update() method I'm calling there actually the synchronized one from
>> >> the trait?
>> >>
>> >>
>> >> Many thanks in advance for your advice,
>> >>
>> >> Sarah
>> >
>> >
>> >
>> >
>> > --
>> > Viktor Klang
>> >
>> > Akka Tech Lead
>> > Typesafe - The software stack for applications that scale
>> >
>> > Twitter: @viktorklang
>> >
>>
>>
>

d_m
Joined: 2010-11-11,
User offline. Last seen 35 weeks 2 days ago.
Re: Understanding how synchronized works / possible bug?

On Mon, Feb 06, 2012 at 04:20:24AM -0800, snim2 wrote:
> 2) Call synchronized as a method of "this" object, where "this"
> extends Runnable. This doesn't work, some array elements do not get
> updated:

The problem here is that your workers aren't using same lock. Each
worker is a different object (with a different lock associated with
this) so obtaining that lock doesn't actually block anyone else.

Whether you use a lock on the array or some other lock, it needs to be
accessible by all threads.

edmondo1984
Joined: 2011-09-14,
User offline. Last seen 28 weeks 3 days ago.
Re: Understanding how synchronized works / possible bug?
Dear Sarah,
your problem is very simple, and I suggest as the other did to read the book from Goletz if you want to handle concurrency in Java. Whenever you use locks, you have to lock the shared mutable object, which is in your case the array. Before Java 5 you could use only synchronized, object.wait and object.notify, from Java 5 you have explicit locks and multi-threaded collections.
To get back to your case, the reason why one works and the other doesn't is because you are doing two very differently things.
1) In your first case, you are correctly synchronizing access around the array, and everything works fine. 2) In the second case, you are synchronizing access around the runnable object, which is accessed only by the thread who runs it, and not the array itself. The array is unguarded and not shielded from multi-thread concurrent writes, and that's why you have your problem.
The synchronized clause use the monitor associated to each Java objects, and once a thread has acquired that monitor, only that thread can enter critical sections associated to that monitor.  You might want to Google for Java Monitor Pattern...hope this clarify the two different behaviours.
Best RegardsEdmondo


2012/2/6 Kevin Wright <kev [dot] lee [dot] wright [at] gmail [dot] com>
I'm curious what your use-case is for looking into `synchronised` at all.  It's a very low-level interface and fraught with dragons (as you've seen).
Unless you have a specific concern over legacy code that uses synchronised (perhaps auto-converted from Java?), you'll find that Atomic/Concurrent primitives, Actors, Agents and Futures should meet all your needs.
Plus, they're also a whole lot more fun :)

2012/2/6 Sarah Mount <mount [dot] sarah [at] gmail [dot] com>
Thanks √iktor, I'm aware that using synchronized is not necessarily a
good idea, I'm not trying to find a good solution to an engineering
problem here, I'm really just trying to understand how synchronized
does and doesn't work. AtomicIntegerArray looks very interesting, and
would probably be useful in a "real" situation, but it doesn't help me
understand synchronized :)

Cheers,

Sarah

2012/2/6 √iktor Ҡlang <viktor [dot] klang [at] gmail [dot] com>:
> Hi Sarah,
>
> Using synchronized is not ideal, for many reasons.
> Look
> into: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicIntegerArray.html
>
> Cheers,
> √
>
>
> On Mon, Feb 6, 2012 at 1:20 PM, snim2 <mount [dot] sarah [at] gmail [dot] com> wrote:
>>
>> Hi there,
>>
>> I'm trying to understand how "synchronized" can be used correctly in
>> Scala to implement a critical section. A colleague and I have
>> implemented some simple / contrived examples that use synchronized,
>> these examples all create an array of 256 Ints, and have two threads
>> iterating over the whole array 100,000 times, updating each array
>> element by adding one to the value. So, once each thread has finished
>> running, every element in the array should be 100000.  I've put the
>> examples in a gist here: https://gist.github.com/1751700
>>
>> We've tried various ways to create the critical section with different
>> levels of success (example output here is from scala 2.8.1.final on
>> Ubuntu Oneiric) and we're trying to understand why each version works
>> or doesn't:
>>
>>
>> 1) Call synchronized as a method of the array, seems to work fine, as
>> you would expect from the doc's:
>>
>> bins.synchronized {
>>    bins(j) += 1
>> }
>>
>>
>> 2) Call synchronized as a method of "this" object, where "this"
>> extends Runnable. This doesn't work, some array elements do not get
>> updated:
>>
>> this.synchronized {
>>    bins(j) += 1
>> }
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 789 iterations missing.
>>
>>
>> 3) Create a new synchronized method and call that, again doesn't seem
>> to work and some elements are not updated:
>>
>> def update(index: Int) : Unit = synchronized {
>>        bins(index) += 1
>> }
>> ...
>> for ...
>>    update(j)
>>
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_example.scala
>> Typical output: Bins are NOT valid. 111560 iterations missing.
>>
>>
>> 4) Use the SynchronizedBuffer trait and the ArrayBuffer class instead
>> of an Array. Use the "update" method which is synchronized in the
>> SynchronizedBuffer trait:
>>
>> val bins = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
>> ...
>> bins.update(j, bins(j) + 1)
>>
>> Full code listing for this example is here:
>> https://gist.github.com/1751700#file_sync_buffer_example.scala
>> Typical output: Bins are NOT valid. 641875 iterations missing.
>>
>>
>> So, why does synchronized not work when called as a method of "this"?
>> Should it never be used in this fashion?
>>
>> Why does 3) not work? I notice that adding a println() statement
>> inside that update() method seems to work, is this a (heisen)bug in my
>> code?
>>
>> Have I used the SyncronizedBuffer trait incorrectly in 4)? Is the
>> update() method I'm calling there actually the synchronized one from
>> the trait?
>>
>>
>> Many thanks in advance for your advice,
>>
>> Sarah
>
>
>
>
> --
> Viktor Klang
>
> Akka Tech Lead
> Typesafe - The software stack for applications that scale
>
> Twitter: @viktorklang
>



snim2
Joined: 2012-02-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Understanding how synchronized works / possible bug?

Thanks, and thanks to Edmondo too. I think my critical mistake was in
thinking of a synchronized block as a critical section of code, rather
than thinking of it as obtaining an exclusive lock at run time. Silly
me, but it's good to learn :)

Cheers,

Sarah

On Mon, Feb 6, 2012 at 13:44, Erik Osheim wrote:
> On Mon, Feb 06, 2012 at 04:20:24AM -0800, snim2 wrote:
>> 2) Call synchronized as a method of "this" object, where "this"
>> extends Runnable. This doesn't work, some array elements do not get
>> updated:
>
> The problem here is that your workers aren't using same lock. Each
> worker is a different object (with a different lock associated with
> this) so obtaining that lock doesn't actually block anyone else.
>
> Whether you use a lock on the array or some other lock, it needs to be
> accessible by all threads.
>

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland