8

In order to avoid race condition, we can synchronize the write and access methods on the shared variables, to lock these variables to other threads.

My question is if there are other (better) ways to avoid race condition? Lock make the program slow.

What I found are:

  • using Atomic classes, if there is only one shared variable.
  • using a immutable container for multi shared variables and declare this container object with volatile. (I found this method from book "Java Concurrency in Practice")

I'm not sure if they perform faster than syncnronized way, is there any other better methods?

thanks

cn1h
  • 1,188
  • 4
  • 16
  • 24
  • 1
    Those are both good alternatives. There are many alternatives which can be used. The applicability of each will depend on your circumstances and exactly what you are trying to achieve. Could you give a little more detail? – Geoff Dec 01 '11 at 11:30
  • just posted answer here https://stackoverflow.com/questions/8340614/java-avoid-race-condition-without-synchronized-lock – mindiga Jun 25 '21 at 10:22
  • Here is my post [Synchronization without locks](https://stackoverflow.com/questions/8340614/java-avoid-race-condition-without-synchronized-lock) – mindiga Jun 25 '21 at 10:23

5 Answers5

8

Avoid state.
Make your application as stateless as it is possible.
Each thread (sequence of actions) should take a context in the beginning and use this context passing it from method to method as a parameter.

When this technique does not solve all your problems, use the Event-Driven mechanism (+Messaging Queue).
When your code has to share something with other components it throws event (message) to some kind of bus (topic, queue, whatever).

Components can register listeners to listen for events and react appropriately.
In this case there are no race conditions (except inserting events to the queue). If you are using ready-to-use queue and not coding it yourself it should be efficient enough.

Also, take a look at the Actors model.

Ahmed Nabil
  • 17,392
  • 11
  • 61
  • 88
AlexR
  • 114,158
  • 16
  • 130
  • 208
  • 1
    I don't think replacing Java's internal monitor locking with external queues/even-driven-mechanisms will improve on performance. Making the application completly stateless might not be an option here either, as the asker already states that it has data to share between the threads. The Actor model might be useful as far as code cleanliness is concerned but again, I think the added overhead will not benefit towards performance. – Shivan Dragon Dec 01 '11 at 11:42
  • 1
    @Andrei Bodnarescu, I absolutely agree with you. I probably expressed myself not exactly. Performance here is not the main issue. Code clearness, modularity and managebility are much more important. I just wanted to say that using event drive approach will not decrease performance as some people afraid. – AlexR Dec 01 '11 at 11:51
  • Agreed, and if I may add, Scala's Actors model implementation is quite nice. And since Scala is one step away from Java for a Java developer, that might be an option. – Shivan Dragon Dec 01 '11 at 11:53
  • about "make the application stateless", if I don't have shared data between threads, but i have something shared between functions in the same thread, I should use ThreadLocal class, right? – cn1h Dec 02 '11 at 07:14
4

Well, first off Atomic classes uses locking (via synchronized and volatile keywords) just as you'd do if you did it yourself by hand.

Second, immutability works great for multi-threading, you no longer need monitor locks and such, but that's because you can only read your immutables, you cand modify them.

You can't get rid of synchronized/volatile if you want to avoid race conditions in a multithreaded Java program (i.e. if the multiple threads cand read AND WRITE the same data). Your best bet is, if you want better performance, to avoid at least some of the built in thread safe classes which do sort of a more generic locking, and make your own implementation which is more tied to your context and thus might allow you to use more granullar synchronization & lock aquisition.

Check out this implementation of BlockingCache done by the Ehcache guys;

http://www.massapi.com/source/ehcache-2.4.3/src/net/sf/ehcache/constructs/blocking/BlockingCache.java.html

Shivan Dragon
  • 15,004
  • 9
  • 62
  • 103
  • 1
    Atomic-classes don't (generally) use synchronized. Their values are volatile, that's correct. Instead of synchronized the sun.misc.Unsafe-Class is used which does CAS-operations as native code. So if the platform your running on supports atomic CAS-operations in assembler, its most likely that the are used instead of synchronizing. – Boris Dec 01 '11 at 13:52
4

Atomics are indeed more efficient than classic locks due to their non-blocking behavior i.e. a thread waiting to access the memory location will not be context switched, which saves a lot of time.

Probably the best guideline when synchronization is needed is to see how you can reduce the critical section size as much as possible. General ideas include:

  1. Use read-write locks instead of full locks when only a part of the threads need to write.
  2. Find ways to restructure code in order to reduce the size of critical sections.
  3. Use atomics when updating a single variable.
  4. Note that some algorithms and data structures that traditionally need locks have lock-free versions (they are more complicated however).
Tudor
  • 61,523
  • 12
  • 102
  • 142
  • "3. Use atomics when updating a single variable." If there are more variables, but they are independent (nerver be used in same function), can I use atomics as well? – cn1h Dec 01 '11 at 14:52
  • Yes, of course. But you will need to use atomics for each of them. – Tudor Dec 01 '11 at 15:09
2

One of the alternatives is to make shared objects immutable. Check out this post for more details.

Community
  • 1
  • 1
Santosh
  • 17,667
  • 4
  • 54
  • 79
1

You can perform up to 50 million lock/unlocks per second. If you want this to be more efficient I suggest using more course grain locking. i.e. don't lock every little thing, but have locks for larger objects. Once you have much more locks than threads, you are less likely to have contention and having more locks may just add overhead.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130