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

Closure is thread-safety?

2 replies
陈resolute
Joined: 2011-05-25,
User offline. Last seen 42 years 45 weeks ago.
Hi,
 I use Parallel collections with scala2.9,but something has worng ? why the result is not the same here is the code
Welcome to Scala version 2.9.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1. 6.0_25).Type in expressions to have them evaluated. Type :help for more information.
scala> var count=0count: Int = 0
scala> (1 to 1000000).par.foreach(x=>if(x%2==0) count+=1)
scala> count res1: Int = 430583
scala>  (1 to 1000000).par.count(_%2==0) res2: Int = 500000
when i usescala> val count=new java.util.concurrent.atomic.AtomicLong() count: java.util.concurrent.atomic.AtomicLong = 0
scala> (1 to 1000000).par.foreach(x=>if(x%2==0) count.getAndIncrement)
scala> countres9: java.util.concurrent.atomic.AtomicLong = 500000
the result is them same.It means Closure is not thread-safety?
Mauro Ciancio
Joined: 2010-10-19,
User offline. Last seen 42 years 45 weeks ago.
Re: Closure is thread-safety?

Hello,
I think this has nothing to do with closures. The fact that you are
using a non protected variable (var count: Int) is what is leading you
to an incorrect value.
The closure is thread-safe, what is not is your access to count.

Regards.

2011/5/24 陈resolute :
> Hi,
>  I use Parallel collections with scala2.9,but something has worng ? why the
> result is not the same
> here is the code
> Welcome to Scala version 2.9.0.final (Java HotSpot(TM) 64-Bit Server VM,
> Java 1.
> 6.0_25).
> Type in expressions to have them evaluated.
> Type :help for more information.
> scala> var count=0
> count: Int = 0
> scala> (1 to 1000000).par.foreach(x=>if(x%2==0) count+=1)
> scala> count
> res1: Int = 430583
> scala>  (1 to 1000000).par.count(_%2==0)
> res2: Int = 500000
> when i use
> scala> val count=new java.util.concurrent.atomic.AtomicLong()
> count: java.util.concurrent.atomic.AtomicLong = 0
> scala> (1 to 1000000).par.foreach(x=>if(x%2==0) count.getAndIncrement)
> scala> count
> res9: java.util.concurrent.atomic.AtomicLong = 500000
> the result is them same.It means Closure is not thread-safety?

Gregory Crosswhite
Joined: 2011-05-18,
User offline. Last seen 42 years 45 weeks ago.
Re: Closure is thread-safety?

On 05/24/2011 07:16 PM, 陈resolute wrote:
> Hi,
> I use Parallel collections with scala2.9,but something has worng ?
why the result is not the same
> here is the code
>
> Welcome to Scala version 2.9.0.final (Java HotSpot(TM) 64-Bit Server
VM, Java 1.
> 6.0_25).
> Type in expressions to have them evaluated.
> Type :help for more information.
>
> scala> var count=0
> count: Int = 0
>
> scala> (1 to 1000000).par.foreach(x=>if(x%2==0) count+=1)
>
> scala> count
> res1: Int = 430583
>
> scala> (1 to 1000000).par.count(_%2==0)
> res2: Int = 500000
>
> when i use
> scala> val count=new java.util.concurrent.atomic.AtomicLong()
> count: java.util.concurrent.atomic.AtomicLong = 0
>
> scala> (1 to 1000000).par.foreach(x=>if(x%2==0) count.getAndIncrement)
>
> scala> count
> res9: java.util.concurrent.atomic.AtomicLong = 500000
>
> the result is them same.It means Closure is not thread-safety?

The problem is not Scala-specific but a problem that is general to
multi-threading. The operation += 1 reads count, increments it, and then
writes it back. While this happens, it is possible that another thread
will have done the same, which means that when you write your own count
back you will have clobbered the other thread's increment in the
process. This is why the total is lower than it should be.

The solution is to replace += with something that guarantees atomic
updates of count, which is exactly what you have done by replacing +=
with AtomicLong to make the updates atomic.

So in short, the problem is not one specific to Scala closures but the
kind of problem you will have to face whenever you write multi-threaded
code.

Hope this helped,
Greg

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