SE205: Practical Work on Concurrent Programming in Java

Laurent Pautet (pautet@telecom-paristech.fr)

Index


1 Lab on Concurrent Programming in Java

This lab does not cover all of the tools Java provides for dealing with concurrency. It illustrates the operation of some of them, in particular the most basic ones, wait() et notify() specified here. You can see the complete documentation of the Java API by following this link. The documentation about semaphores is available here. Course material on tasks can be found here. You will find all the sources in this compressed archive. To uncompress, use GNU tar:

tar zxf src.tar.gz

1.1 Process creation and termination in order of creation

We consider the BoundedBufferMain.java file. This program creates producers and consumers which exchange data in using a shared buffer, as was the case for the C version we implemented previously. In this section, we focus primarily on creation producers and consumers.

The producers are described in the Producer class of the Producer.java file and produce data (integers) in a circular buffer described in the BoundedBuffer class that we will protect against concurrent access. Consumers are found as for them in the class Consumer of the file Consumer.java and consume the produced data in the same way.

Concurrent access for producers and consumers will be possible following several semantics. We can have blocking, non-blocking, or timed blocking accesses. For this latter case, the blocking operation cannot last more than a given time.

Producers and consumers adopt a periodic behavior. Each period starting from a common time startTime specified in Utils class of file Utils.java, they produce or consume data and then wait for the next period to start over. For example, producers resume their activity every startTime + n * producerPeriod where n represents the number of activations.

More generally, the configuration parameters can be found specified in the Utils class of the Utils.java file. The number of producers (nProducers, that of consumers (nConsumers), the size of the circular buffer (bufferSize), the semantics of accesses to it (semantics) or the periods of producers (producerPeriod) and consumers (consumerPeriod) are configured using a scenario file which name is passed on the command line.

Complete BoundedBufferMain to create as many producers and consumers than requested and then wait for the termination of the producers and consumers. You can use the file from scenario test - 00.txt to verify that you create the number correct of producers and consumers.


1.2 Buffer protected against concurrent access (var cond / blocking)

We are going to implement a circular buffer protected against concurrent accesses in the NatBoundedBuffer class of the file NatBoundedBuffer.java. To do this, we can use the implantation of an unprotected circular pad that is provided in the BoundedBuffer class of the BoundedBuffer.java file. Note that unlike the C version, the NatBoundedBuffer class can inherit from the BoundedBuffer class.

Complete the NatBoundedBuffer class knowing that you must use only native Java constructs, i.e. synchronized, wait, notify and notifyAll.

Complete the get and put methods so that it offers the following services:

Test the proper functioning of the protected circular buffer using the BoundedBufferMain class. You will use the scenario of test, test-00.txt. Note instants consumers and producers are supposed to block. Normally with this semantical (non-blocking), all data produced must be consumed.


1.3 Buffer protected against concurrent access (var cond / non-blocking)

We are going to implement a circular buffer protected against concurrent accesses in the NatBoundedBuffer class of the file NatBoundedBuffer.java. This time, the semantics of these accesses is non-blocking. If the operation cannot take place immediately, it does not block but returns a special value. The producer will signal with a binary return code whether it succeeded in inserting immediately an element in the buffer. The consumer will report by a null pointer or a non-null pointer on the data whether it succeeded in extracting immediately an element in the buffer. The tampon should always be protected against concurrent access.

Complete the remove and add methods so that they offer the proposed services. Test the correct functioning of the circular buffer protected with the BoundedBufferMain class. You will use the test cases, test-01.txt and test-02.txt. We verify that consumers and producers do not block and proceed as expected. In the first scenario, there are more producers than consumers. Thus, the buffer will be filled and some producers will fail to file their data. In the second scenario, on the opposite, the consumers will fail to extract data.


1.4 Buffer protected against concurrent access (cond var / timed)

We are going to implement a circular buffer protected against concurrent accesses in the NatBoundedBuffer class of the file NatBoundedBuffer.java. This time, the semantics of these accesses is timed blocking. If the operation cannot be completed immediately, it blocks until it can take place, but waits until a given deadline (which corresponds to a date i.e. a time absolute). If the operation fails, it returns a special value like previously.

If the operation cannot take place immediately, it does not block but returns a special value. The producer signals with a binary return code whether it succeeded in inserting immediately an element in the buffer. The consumer reports by a null pointer or a non-null pointer on the data if it succeeded in extracting immediately an element in the buffer. The tampon should always be protected against concurrent access.

Complete the poll and offer methods so that they offer the indicated services. Test the correct functioning of the circular buffer protected thanks to the BoundedBufferMain class. You will use the test cases, test-03.txt and test-04.txt. You will check that consumers and producers remain blocked at most until the deadline and execute as expected.


1.5 Buffer protected against concurrent access (semaphore / blocking)

We are going to implement a circular buffer protected against concurrent accesses, but instead of using native Java constructs for blocking execution, you will use semaphores, which are provided in the Java package java.util.concurrent.Semaphore. You can still use the implantation of an unprotected circular pad that is provided in the BoundedBuffer class of the BoundedBuffer.java file. You will modify the class SemBoundedBuffer in the SemBoundedBuffer.java file, and more precisely the get and put methods. You will use the same scenarios as for the implementation based on native constructions.


1.6 Buffer protected against concurrent access (semaphore / non-blocking)

We keep implementing a circular buffer protected against concurrent accesses using semaphores. This time we focus on non-blocking accesses. Modify the SemBoundedBuffer class accordingly and in particular the remove and add methods. You can use the same scenarios as those of the implementation based on native constructs.


1.7 Buffer protected against concurrent access (semaphore / timed)

We keep implementing a circular buffer protected against concurrent accesses using semaphores. This time we focus on timed blocking accesses. Modify the SemBoundedBuffer class accordingly and in particular the remove and add methods. You can use the same scenarios as those of the implementation based on native constructs.