2

HashTable is a thread-safe collection but does initializing it with an ArrayList (which is not thread-safe) as value endanger the whole thread-safety aspect?

 Hashtable <Employee, ArrayList<Car>> carDealership = new Hashtable<>();

Further on, I am planning to wrap every action of ArrayLists in a synchronized block to prevent any race-conditions when operating with any methods.

Yet I haven't declared the ArrayLists in the HashTable as synchronized lists, this being achieved with the following code

 Collections.synchronizedList(new ArrayList<>())

This will happen when I will be adding ArrayLists to the HashTable obviously.

How can I be sure that the ArrayLists in the HashTable are thread-safe?

Is it enough to pass a thread-safe ArrayList to the put() method of the hashTable and I'm good to go? (and not even worry about the constructor of the HashTable?) Therefore the put() method of the HashTable doesn't even recognize if I am passing a thread-safe/unsafe parameter?

Note: Thread-safety is a requirement. Otherwise I wouldn't have opted for this implementation.

Catalin Ghita
  • 794
  • 8
  • 26
  • Side note: `Hashtable` is thread-safe, but is there a specific reason why you are not using [ConcurrentHashMap](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ConcurrentHashMap.html)? It offers a vastly more powerful API. – Hulk Apr 05 '18 at 14:42
  • @Hulk Mainly because HashTable has a fail-fast iterator and I ma trying to test this out as well. Using ConccurentHashMap would still not solve my issue of having to pass a List as value. – Catalin Ghita Apr 05 '18 at 14:50
  • Yeah ok, iteration on the `ConcurrentHashMap` iterates over a snapshot and does not fail with `ConcurrentModificationException`. I did not mean to imply that using `ConcurrentHashMap` would solve your problem, I was just curious why you consider using the ancient `Hashtable` instead. – Hulk Apr 05 '18 at 14:55
  • Replacing a List (that was declared as synchronized) within `ConcurrentHashMap` or `Hashtable` would rise indeed a non-safe thread issue as the answer below states? – Catalin Ghita Apr 05 '18 at 14:58
  • @Hulk As I said, I am planning to wrap every action of ArrayLists in a synchronized block to prevent any race-conditions when operating with any methods. Now back to the question answer, the poster stands up to the fact that HashTable might actually leave references in an invalid state. Is my solution thread-safe after-all? – Catalin Ghita Apr 05 '18 at 15:39

2 Answers2

1

The only way to ensure that the values in the Hashtable or ConcurrentHashMap are thread-safe is to wrap it in a way that prevents anyone from adding something that you don't control. Never expose the Map itself or any of the Lists contained in it to other parts of your code. Provide methods to get snapshot-copies if you need them, provide methods to add values to the lists, but make sure the class wrapping the map is the one that will create all lists that can ever get added to it. Iteration over the "live" lists in you map will require external synchronisation (as metioned in the JavaDocs of synchronizedList).

Both Hashtable and ConcurrentHashMap are thread-safe in that concurrent operations will not leave them in an invalid state. This means e.g. that if you invoke put from two threads with the same key, one of them will return the value the other inserted as the "old" value. But of course you can't tell which will be the first and which will be second in advance without some external synchronization.

The implementation is quite different, though: Hashtable and the synchronized Map returned by Collections.synchronizedMap(new HashMap()); are similar in that they basically add synchronized modifiers to most methods. This can be inefficient if you have lots of threads (i.e. high contention for the locks) that mostly read, but only occasionally modify the map. ConcurrentHashMap provides more fine grained locking:

Retrieval operations (including get) generally do not block

which can yield significantly better performance, depending on your use case. I also provides a richer API with powerful search- and bulk-modification-operations.

Hulk
  • 6,399
  • 1
  • 30
  • 52
0

Yes, using ArrayList in this case is not thread safe. You can always get the object from the table and operate on it.

CopyOnWriteArrayList is a good substitue for it.

But you still have the case, when one thread takes (saves in a variable) the collection, and the other thread replaces with another one.
If you are not going to replace the lists inside the table, then this is not a problem.

Aleksandr
  • 428
  • 2
  • 8
  • 14
  • Unfortunately I have to operate write operations too, this kind of disqualifying `CopyOnWriteArrayList`. But why using the `ArrayList` in this case if not thread safe? As long as I only add synchronized Lists to the Hashtable and all operations with the certain Lists will be enclosed in `synchronized blocks`? – Catalin Ghita Apr 05 '18 at 14:24
  • @CatalinGhita CopyOnWriteArrayList is thread safe and there shouldn't be any major difference using this or synchronized lists. What I am saying is that if you are going to replace the existing list for some Emloyee (something you quite probably may not be doing), then this will create a non thread safe case. – Aleksandr Apr 05 '18 at 14:31
  • Can you please elaborate why replacing the List would create a non-thread safe case? It is pretty much the same as adding a thread-safe List to the HashTable – Catalin Ghita Apr 05 '18 at 14:40
  • @CatalinGhita imagine one thread saving a list from employee "bob" in a variable to work on it later. Meanwhile another thread replaces the list for "bob" with another list. Then, when the first thread starts working on the list it saved, it is going to be operating on a probably outdated list and any changes done to it won't be reflected in the list in the table. – Aleksandr Apr 05 '18 at 14:46
  • Why would it work on an outdated list? As long as the List itself is marked as synchronized – Catalin Ghita Apr 05 '18 at 14:52
  • @CatalinGhita because it will be a different list. – Aleksandr Apr 05 '18 at 14:52
  • How could the list be different? As long as other threads will operate on the thread-safe list? – Catalin Ghita Apr 05 '18 at 14:55
  • You are making me repeat the same thing for the fourth time. Plase read [this](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value). – Aleksandr Apr 05 '18 at 15:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168325/discussion-between-catalin-ghita-and-aleksandr-mukhalov). – Catalin Ghita Apr 05 '18 at 15:08