Anda di halaman 1dari 7

Technical University of Moldova CIM Faculty

Report
at Parallel and Concurrent Programming

Theme: Multi-threading programming

Done by:

st., gr. FAF-081 Nicoara Alexei superior. lecture. Ciorb Dumitru

Verified by:

Chisinau 2011

Topic: Multi-threading programming Objective: Learn how to create, run, suspend and stop threads in Java. Study the elements of thread communication and synchronization. 1 The Basics 1.1 Threads A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently. Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon. When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs: The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place. All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method. There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started. [0] 1.2 Semaphores Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly. Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource. For example, here is a class that uses a semaphore to control access to a pool of items: Before obtaining an item each thread must acquire a permit from the semaphore, guaranteeing that an item is available for use. When the thread has finished with the item it is returned back to the pool and a permit is returned to the semaphore, allowing another thread to acquire that item. Note that no synchronization lock is held when acquire() is called as that would prevent an item from being returned to the pool. The semaphore encapsulates the synchronization needed to restrict access to the pool, separately from any synchronization needed to maintain the consistency of the pool itself. A semaphore initialized to one, and which is used such that it only has at most one permit available, can serve as a mutual exclusion lock. This is more commonly known as a binary semaphore, because it only has two states: one permit available, or zero permits available. When used in this way, the binary semaphore has the property (unlike many Lock implementations), that the "lock" can be released by a thread other than the owner (as semaphores have no notion of ownership). This can be useful in some specialized contexts, such as deadlock recovery.

The constructor for this class optionally accepts a fairness parameter. When set false, this class makes no guarantees about the order in which threads acquire permits. In particular, barging is permitted, that is, a thread invoking acquire() can be allocated a permit ahead of a thread that has been waiting - logically the new thread places itself at the head of the queue of waiting threads. When fairness is set true, the semaphore guarantees that threads invoking any of the acquire methods are selected to obtain permits in the order in which their invocation of those methods was processed (first-in-first-out; FIFO). Note that FIFO ordering necessarily applies to specific internal points of execution within these methods. So, it is possible for one thread to invoke acquire before another, but reach the ordering point after the other, and similarly upon return from the method. Also note that the untimed tryAcquire methods do not honor the fairness setting, but will take any permits that are available. Generally, semaphores used to control resource access should be initialized as fair, to ensure that no thread is starved out from accessing a resource. When using semaphores for other kinds of synchronization control, the throughput advantages of non-fair ordering often outweigh fairness considerations. This class also provides convenience methods to acquire and release multiple permits at a time. Beware of the increased risk of indefinite postponement when these methods are used without fairness set true. [1]

The Problem

The task for this laboratory work is to create a mechanism of synchronization between different threads using the tools provided by Java concurrent library. Each thread should send a message to another thread at an arbitrary time of its execution. Upon receiving the message the other thread will start its own execution. The relationship between different threads is shown in the figure 1.

Figure 1 Problem diagram

The Solution

To implement the messaging between to threads I used the Semaphores provided by Java concurrent library. Semaphores are one of the most basic tools for synchronization of threads in Java [2], so it fits the requirements of the problem perfectly. Each thread has a list of semaphores it should acquire before it can start. These semaphores represent the arrows which enter in the thread in figure 1. Also, each thread has a list of semaphores it should release at some moment of its execution, those are the arrows which are leaving the thread in figure 1. The state diagram which represents the internal structure of the Thread class is represented in the figure 2.

Figure 2 State diagram of the Thread This approach is implemented very easily in Java by using two ArrayLists , one for holding the start semaphores and another one for holding the end semaphores. This process is represented in the figure 3. public void run() { try { for (Semaphore semaphore: startSemaphores) { semaphore.acquire(); } System.out.println(id); sleep(300); for (Semaphore semaphore: endSemaphores) { semaphore.release(); } } catch (InterruptedException e) { e.printStackTrace(); } } Figure 3 run() method of the MyThread class The lists of semaphores are populated from in main() function by specifying which thread should wait which thread. This is done by the method of the MyThread class waitFor() which is presented in figure 4. public void waitFor(MyThread thread) { Semaphore semaphore = new Semaphore(0); thread.addEndSemaphore(semaphore); startSemaphores.add(semaphore); } Figure 4 Method implementing the linking between threads The semaphores are created with the number of permits set to zero, because the thread should not be able to acquire the semaphore before it was released by the thread which controls the start moment.

Conclusion

In current world appears a lot of problems which require to solve a lot of tasks in parallel, without blocking each other, a solution for this problem is to use multithreading tools of your selected programming language. Java provides a very useful library for creating multithreaded programs which is situated in java.util.concurrent package. It implements the threading mechanism in a pseudo-parallel way, executing each thread in a concurrent way. Also, it provides a lot of useful tools for synchronization of the threads. Java provides a set of synchronization classes, mot used of them are Semaphore, CyclicBarrier and CountDownLatch. Semaphore is used to allow only a fixed amount of threads to use a shared resource by acquiring and releasing a shared Semaphore shared between two threads. CyclicBarriers is a synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CountDownLatch allows one or more threads to wait until a set of operations being performed in other threads completes. For this task I selected the Semaphores because they allow to stop a thread until the other thread which has a shared Semaphore with it will not release it. The solution of creating a Semaphore for each connection between two threads is a very expensive one, but it gives a lot of flexibility to the system which allows execution of every possible combination of the dependencies in the task. Also it provides a intuitive workflow of the program, which helps in understanding the solution of this multithreading problem and enhance studying.

References

[0] Thread, Java Documentation, Oracle http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html [1] Semaphore, Java Documentation, Oracle http://download.oracle.com/javase/1,5,0/docs/api/java/util/concurrent/Semaphore.html [2] Synchronizing Java Threads, Java Developers Journal http://www2.sys-con.com/itsg/virtualcd/Java/archives/0701/goenka/index.html

Anda mungkin juga menyukai