scala thread safe HashSet
Asked Answered
N

2

5

What are the possible ways to make a HashSet thread safe? Saw some samples as given below.

var test = new mutable.HashSet[Long] with mutable.SynchronizedSet[Long]

SynchronizedSet is deprecated at present. Any suggestions or samples will be very much helpful.

Nigro answered 6/12, 2016 at 10:58 Comment(2)
Note that the API docs suggest what you could use instead of the deprecated SynchronizedSet.Caerleon
They suggest to use ConcurrentHashMap I am interested in SetNigro
C
18

As the API documentation of scala.collection.mutable.SynchronizedSet suggests, you can use java.util.concurrent.ConcurrentHashMap[A, Unit] instead.

If you want it to look like a Set instead of like a Map, then you can use java.util.Collections.newSetFromMap to add a wrapper around the Map to make it look like a Set:

def createSet[T]() = java.util.Collections.newSetFromMap(
  new java.util.concurrent.ConcurrentHashMap[T, java.lang.Boolean])

This will, however, return a Java Set. You can wrap this as a scala.collection.mutable.Set:

def createSet[T]() = {
  import scala.collection.JavaConverters._
  java.util.Collections.newSetFromMap(
    new java.util.concurrent.ConcurrentHashMap[T, java.lang.Boolean]).asScala
}

Now you can create a synchronized set with elements of a specific type, for example Long, like this:

val set = createSet[Long]
Caerleon answered 6/12, 2016 at 11:20 Comment(5)
Is there a way to check if my mutable.Set[T] is the concurrent or basic version?Whipstock
I'm a little concerned that your mutable.Set is not actually concurrentWhipstock
@Whipstock It's a wrapper around a Java ConcurrentHashMap. The wrapper doesn't do anything that makes it not-concurrent.Caerleon
Thanks @Caerleon . I've added a new Q&A here which (inductively) proves the concurrency of sets created in this way. #56014003Whipstock
Also, you can create it in this manner: java.util.concurrent.ConcurrentHashMap.newKeySet[Int]().asScala. A little more concise.Whipstock
S
0

Building upon Jespers solution scala thread safe HashSet:

val myConcurrentSet = new java.util.concurrent.ConcurrentHashMap[String, Boolean]().keySet(true)

This way you use only the keys of the Map, thus a Set. Also it's needed to configure the default value for all the values, here as true but could be false as well. Failing to set this default value for key additions, when adding a key the method will raise:

[info]   java.lang.UnsupportedOperationException:
[info]   at java.base/java.util.concurrent.ConcurrentHashMap$KeySetView.add(ConcurrentHashMap.java:4651)

as v will be null in java.base/java.util.concurrent.ConcurrentHashMap.add(K e):

/**...
* Throws:
* ...
* UnsupportedOperationException – if no default mapped value for additions was provided
**/
public boolean add(K e) {
            V v;
            if ((v = value) == null)
                throw new UnsupportedOperationException();
            return map.putVal(e, v, true) == null;
        }
Singultus answered 19/9, 2023 at 9:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.