25

As far as I know, wait() and notify() have been replaced with better concurrency mechanisms. So, what better alternative would you choose, say for implementing a synchronized queue?

In what sense exactly are they "better"?

Edit: This ("implement a synchronous queue") is an interview question. An acceptable answer cannot use BlockingQueue or other queue implementation. It might, however, use other synchronization constructs such as CountDownLatch. I do not have an exhaustive list of allowed and forbidden classes - use your heads.

Community
  • 1
  • 1
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 7
    I wouldn't implement a synchronized queue. I'd use one of the many implementations of BlockingQueue: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html – Mike Daniels Feb 06 '11 at 07:28
  • 1
    @Mike - I'm preparing for job interviews. In real life, I would use something existing rather than reinvent. – ripper234 Feb 06 '11 at 07:29
  • Then I'm afraid I don't understand the question. Synchronized blocks and wait/notify have been replaced by higher-level abstractions in the form of the classes in the java.util.concurrent package, not by new language constructs. If the intent of the question is to make use of some of the java.util.concurrent classes, which ones are we excluded from answering with? – Mike Daniels Feb 06 '11 at 07:34
  • @Mike - I don't have an exhaustive list of allowed and forbidden classes, but obviously BlockingQueue is on the forbidden list. – ripper234 Feb 06 '11 at 07:37

5 Answers5

28

synchronized/wait()/notify()/notifyAll() have been directly replaced by the Lock class methods lock()/unlock()/newCondition() and Condition's await()/signal()/signalAll().

There are several benefits to these, for a start allowing additional semantics such as fairness policies, as well as features such as distributed locking. The support for multiple Condition objects allows for much finer-grained signalling as well as uninterruptible waiting and waiting until some time etc.

For instance, the linked code has separate objects it attempts to use for signalling (which will fail due to the fact that the relevant monitors aren't held when waiting). This is directly replaceable by the use of a single Lock with multiple conditions.

In terms of improvements, the additional functionality may be of value. In Java5 the explicit Lock implementations actually performed better than the JVM monitors, but they basically nicked Doug Lea's code for the JVM and performance is now roughly equivalent.

Jed Wesley-Smith
  • 4,686
  • 18
  • 20
  • I don't think it's accurate to say the language primitives have been "replaced". Infact in Java 8+ some uses (e.g. of ConcurrentHashMap) have actually switched back to synchronized / wait / notify as performance is better than using the awkward java.util.concurrent.locks libraries ("awkward" quote taken from Javadocs themselves!) – Sina Madani Feb 20 '19 at 12:33
7

There are pretty much implementations already existing in the java.util.concurrent package. E.g. - ArrayBlockingQueue, DelayQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue.

Also wait() and notify() have not been replaced. New utilities have been introduced that provide additional functionalities and performance benefits. See for example the java.util.concurrent.locks package.

I would recommend you to read this introduction. It provides a high overview that should answer your question.

Cheers.

Edit 1: Ok, then for example you can use an implementation of java.util.concurrent.locks .Lock to implement a dequeue operation that times-out and in the same time grants fairness to the threads accessing the queue. Such implementation is ReentrantLock which has a constructor that accepts the fairness policy. The timed tryLock() favors this property. Also you can add some debugging support for counting the waiting threads on the queue, etc. This would be much more difficult to implement simply with wait() and notify() I assume.

In conclusion ReentrantLock is "better" than the low level counterparts in its extended capabilities. The basic behavior is the same though. If you do not need these extras wait() and notify() are still acceptable alternative.

randers
  • 5,031
  • 5
  • 37
  • 64
Lachezar Balev
  • 11,498
  • 9
  • 49
  • 72
3

Reading the source of the ArrayBlockingQueue implementation reveals the use of Conditions as a replacement for the Object monitor methods "wait/notify/notifyAll". Also, a ReentrantLock is used instead of the "synchronized" keyword to attain similar mutual exclusion behavior and semantics. So it seems the java.util.concurrent.locks package is what you're looking for. These new interfaces are better because they provide additional functionality not possible with the original synchronization and locking constructs, such as multiple wait-sets and selective read or write locks (rather than always both read and write).

The java.util.concurrent.atomic package also provides interfaces to compare-and-swap instructions which are useful for non-blocking algorithms, which are potentially much faster than their blocking alternatives but have their own challenges.

maerics
  • 151,642
  • 46
  • 269
  • 291
1

park() unpark() methods of LockSupport class seems to be useful in this case. I also faced same questions and while searching on net, found a clue in this discussion.

Synchronization vs Lock

But I need to understand the concepts further to create a sample application.

Community
  • 1
  • 1
Kaushik Lele
  • 6,439
  • 13
  • 50
  • 76
0

How about using Semaphore from the Concurrent package? Using a binary Semaphore as a intrinsic lock and two counting Semaphores to set a bound on the size of the queue?