940 likes | 1.21k Views
Concurrent Programming. Course objective. Introduction to Thread and MultiThread Creating & Managing Threads Life Cycle of a Thread Thread class methods Daemon Threads Thread scheduling & priorities Thread Synchronization Thread Interaction Thread Deadlock Runnable Interface.
E N D
Course objective Introduction to Thread and MultiThread Creating & Managing Threads Life Cycle of a Thread Thread class methods Daemon Threads Thread scheduling & priorities Thread Synchronization Thread Interaction Thread Deadlock Runnable Interface
Learning Approach The following are strongly suggested for a better learning and understanding of this course: Noting down the key concepts in the class Analyze all the examples / code snippets provided Study and understand the self study topics Completion and submission of all the assignments, on time Completion of the self review questions in the lab guide Study and understand all the artifacts including the reference materials / e-learning / supplementary materials specified Completion of the project (if application for this course) on time inclusive of individual and group activities Taking part in the self assessment activities Participation in the doubt clearing sessions
Introduction to Thread and MultiThread Session 1
Introduction to Thread and MultiThread A thread is the smallest unit of executable code that performs a particular task. Java supports multithreading. An application can contain multiple threads. Each thread is specified a particular task which is executed concurrently with the other threads. This capability of working with multiple threads is called Multithreading.
Processes and Threads • A process has a self-contained execution environment. A process generally has a complete, private set of basic run-time resources; in particular, each process has its own memory space. • Most implementations of the Java virtual machine run as a single process. Multiprocess applications are beyond the scope of this lesson.
Processes and Threads • Threads are sometimes called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process. • Threads exist within a process — every process has at least one. • Multithreaded execution is an essential feature of the Java platform. Every application has at least one thread
Creating & Managing Threads Session 2
Creating & Managing Threads When you execute your Java programs, there is already one thread that is running and it is the main thread. This main thread is important for two reasons: It is the thread from which child threads will be created. It is the last thread to finish execution. The moment the main thread stops executing, the program is terminated. Though this main thread is created automatically with the program execution, it can be controlled through a thread object (Thread).
Creating & Managing Threads (cont.) You can work with threads in two ways: Declare the class to be a sub-class of Class Thread where you need to override the run method of Class Thread. class MyThread extendsThread { public void run( ) { //your thread implementation here... } } Declare the class that implements Runnable. Then define the run( ) method. class MyThread implementsRunnable { public void run( ) { //your thread implementation here... } }
Creating & Managing Threads (cont.) In the Thread subclass, implement the run() method. The signature of run() must be right. run() is the entry point or starting point (or main) of your thread. To start a thread, create an object from your Thread class. Send the "start()" method to the thread object. This will create the new thread, start it as an active entity in your program, and call the run() method in the thread object. Do not call the run() method directly.
Creating & Managing Threads (cont.) First, have your class implement the Runnable interface, which has one method, run(). This run() plays the same role as the run() in the Thread subclass Second, create an instance of the Thread class, passing an instance of your class to the constructor. Finally, send the thread object the start() method.
Creating & Managing Threads (cont.) There are several constructors in the class Thread. Two of which are mentioned here: public Thread(String threadname) Constructs a thread with the name as threadname public Thread( ) Constructs a thread with the name "Thread" which is concatenated with a digit, such as Thread-1, Thread-2 and so on.
Example: Giving name to a thread: Creating & Managing Threads (cont.) Practice Modify the code so that it produce one Mom and one Dad
Life Cycle of a Thread Session 3
Life Cycle of a Thread Runnable wait() Running sleep() suspend() Not-Runnable yield() Sleeping Blocked Suspended Scheduler start() resume() new Thread Ready Time expires notify() run() finishes Dead
Life Cycle of a Thread • A thread that has just created is in a born state. The thread does not immediately start running after it is created. It waits for its start( ) method to be called, and even then it is in a ready to run state. • This thread enters the running state when the system allocates the processor to the thread. • You can temporarily halt the execution of the thread for a period of time with the help of sleep( ) method. The thread then enters the sleeping state which becomes ready after the sleep time expires. Sleeping threads do not use the processor. • The thread enters the waiting state when a running thread calls wait. The thread again enters a ready state after the call to notify is given by other thread associated with that object. • The thread enters a blocked state when the thread is performing the Input/Output operations and becomes ready when the I/O it is waiting for is completed. • The thread enters a dead state after the complete execution of the run() method or its stop method is called.
Thread class methods Session 4
Java Thread Primitive Deprecation These method are deprecated: Thread.suspend() Thread.resume() Thread.stop() Thread.destroy()
Why is Thread.stop deprecated? • Why? • Cause this method is inherently unsafe. • Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked. If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. • So what replace Thread.stop? • Many uses of stop() should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt() method should be used to interrupt the wait.
Why are Thread.suspend and Thread.resume deprecated? • Why? • This method has been deprecated, as it is inherently deadlock-prone. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed. • If the thread that would resume the target thread attempts to lock this monitor prior to calling resume, deadlock results. Such deadlocks typically manifest themselves as "frozen" processes. • So what should I use instead? • As with Thread.stop, the prudent approach is to have the "target thread" poll a variable indicating the desired state of the thread (active or suspended). When the desired state is suspended, the thread waits using Object.wait. When the thread is resumed, the target thread is notified using Object.notify.
Why is Thread.destroy deprecated? • This method was originally designed to destroy this thread without any cleanup. Any monitors it held would have remained locked. However, the method was never implemented. If it were to be implemented, it would be deadlock-prone in much the manner of Thread.suspend().
Thread class methods (cont.) Thread.join()– Waiting for Thread to end [this method is blocked until the thread is die] If thread A sends the "join()" method to thread B, then thread A will be "not runnable" until thread B's run methods ends. At that time thread A becomes runnable.
Thread class methods (cont.) Sleep state Thread.sleep causes the current thread to pause execution for a specified period. The thread does not lose ownership of any monitors. After specified period, it will awakens. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system. Using by call sleep(long millis) or sleep(long millis, int nanos)
ThreadTester.java 01 // ThreadTester.java 02 // Multiple threads printing at different intervals. 03 04 publicclass ThreadTester { 05 06 publicstaticvoid main( String [] args ) 07 { 08 // create and name each thread 09 PrintThread thread1 = new PrintThread( "thread1" ); 10 PrintThread thread2 = new PrintThread( "thread2" ); 11 PrintThread thread3 = new PrintThread( "thread3" ); 12 13 System.err.println( "Starting threads" ); 14 15 thread1.start(); // start thread1 and place it in ready state 16 thread2.start(); // start thread2 and place it in ready state 17 thread3.start(); // start thread3 and place it in ready state 18 19 System.err.println( "Threads started, main ends\n" ); 20 21 } // end main 22 23 } // end class ThreadTester 24
ThreadTester.java 25 // class PrintThread controls thread execution 26 class PrintThread extends Thread { 27 privateint sleepTime; 28 29 // assign name to thread by calling superclass constructor 30 public PrintThread( String name ) 31 { 32 super( name ); 33 34 // pick random sleep time between 0 and 5 seconds 35 sleepTime = ( int ) ( Math.random() * 5001 ); 36 } 37 38 // method run is the code to be executed by new thread 39 publicvoidrun() 40 { 41 // put thread to sleep for sleepTime amount of time 42 try { 43 System.err.println( 44 getName() + " going to sleep for " + sleepTime ); 45 46 Thread.sleep( sleepTime ); 47 } 48
ThreadTester.java 49 // if thread interrupted during sleep, print stack trace 50 catch ( InterruptedException exception ) { 51 exception.printStackTrace(); 52 } 53 54 // print thread name 55 System.err.println( getName() + " done sleeping" ); 56 57 } // end method run 58 59 } // end class PrintThread Output: Starting threads Threads started, main ends thread1 going to sleep for 1217 thread2 going to sleep for 3989 thread3 going to sleep for 662 thread3 done sleeping thread1 done sleeping thread2 done sleeping
Daemon Threads A Java program is terminated only after all the threads die. There are two types of threads in a Java program User threads Daemon threads The threads that are created by the Java Virtual Machine on your behalf are called daemon threads. Java provides a garbage collector thread that reclaims dynamically allocated memory, that is no longer needed. This thread runs as a low priority thread that may be the only thread left running in the JVM. And since all the other threads have terminated, there is no more work to be done and so the JVM can exit. Therefore, the garbage collection is marked as a daemon thread. The thread class has two methods that deal with daemon threads. public void setDaemon(boolean on) public boolean isDaemon( )
SimpleThreads Example • The following example brings together some of the concepts of this section. SimpleThreads consists of two threads. The first is the main thread that every Java application has. The main thread creates a new thread from the Runnable object, MessageLoop, and waits for it to finish. If the MessageLoop thread takes too long to finish, the main thread interrupts it. • The MessageLoop thread prints out a series of messages. If interrupted before it has printed all its messages, the MessageLoop thread prints a message and exits.
SimpleThreads.java publicclass SimpleThreads { //Display a message, preceded by the name of the current thread staticvoid threadMessage(String message) { String threadName = Thread.currentThread().getName(); System.out.format("%s: %s%n", threadName, message); } privatestaticclass MessageLoop implements Runnable { publicvoid run() { String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", "A kid will eat ivy too" }; try { for (int i = 0; i < importantInfo.length; i++) { Thread.sleep(4000); //Pause for 4 seconds threadMessage(importantInfo[i]); //Print a message } } catch (InterruptedException e) { threadMessage("I wasn't done!"); } } }
SimpleThreads.java publicstaticvoid main(String args[]) throws InterruptedException { //Delay, in milliseconds before we interrupt MessageLoop thread. long patience = 10000; threadMessage("Starting MessageLoop thread"); long startTime = System.currentTimeMillis(); Thread t = new Thread(new MessageLoop()); t.start(); threadMessage("Waiting for MessageLoop thread to finish"); //loop until MessageLoop thread exits while (t.isAlive()) { threadMessage("Still waiting..."); //Wait maximum of 1 second for MessageLoop thread to finish. t.join(1000); if (((System.currentTimeMillis() - startTime) > patience) && t.isAlive()) { threadMessage("Tired of waiting!"); t.interrupt(); //Shouldn't be long now -- wait indefinitely t.join(); } } threadMessage("Finally!"); } }
Output main: Starting MessageLoop thread main: Waiting for MessageLoop thread to finish main: Still waiting... main: Still waiting... main: Still waiting... main: Still waiting... main: Still waiting... Thread-0: Mares eat oats main: Still waiting... main: Still waiting... main: Still waiting... main: Still waiting... Thread-0: Does eat oats main: Still waiting... main: Tired of waiting! Thread-0: I wasn't done! main: Finally!
Thread scheduling & priorities Session 5
Thread scheduling & priorities Most of the Java programs work with multiple threads. The CPU logical core is capable of running only one thread at a time. When there are more that two threads in a program, that are of equal priority, each thread wants the CPU time and the threads compete with each other to access this resource. It is the programmer, or the Java Virtual Machine or the operating system that need to ensure that the CPU is shared between the threads. This is called scheduling of threads.
Thread scheduling & priorities (cont.) Every thread in Java has its own priority. This priority is in the range Thread.MIN_PRIORITY = 1 Thread.MAX_PRIORITY = 10 By default, a thread has a priority of Thread.NORM_PRIORITY, a constant of 5. Every new thread that is created, inherits the priority of the thread that creates it. The priority of the thread can be adjusted with the method called setPriority(int). To get priority, use method getPriority().
Thread scheduling & priorities (cont.) Some Java platforms support the concept of time slicing. In this, every thread receives a small portion of processor time which is called a quantum. The thread can perform its task during this quantum. After the time period is over, even if the thread has not finished its execution, the thread is given no more time to continue and the next thread of equal priority takes the charge of the processor time. The Java scheduler does this, where all equal high-priority threads are timesliced.
Thread scheduling & priorities (cont.) Last thread with highest priority (6) will run first
Thread Synchronization Session 6
Thread Synchronization While working with multiple threads, it may so happen that more than one thread wants to access the same variable at the same time. In that case, we need to allow one thread to finish its task completely and then allow the next thread to execute. This can be attained with the help of the synchronized( ) method. This method tells the system to put a lock around a particular method. Every object with a synchronized method is a monitor that lets only one thread at a time to execute. After execution, the lock on the object is released and the next priority thread starts running.
Bugs in multi threads • These bugs are introduced when multiple threads access shared data. • Because they are unpredictable, these bugs can be difficult to detect and fix. • So we should have a example to make clear about these bugs.
Counter.java publicclass Counter { privateint c = 0; // Start with 0 publicvoid increment() { c++; // Increase by 1 } publicint value() { return c; } }
ThreadInterference.java publicclass ThreadInterference extends Thread { private Counter counter = new Counter(); staticvoid threadMessage(String message) { String threadName = Thread.currentThread().getName(); System.out.format("%s: %s%n", threadName, message); } @Override publicvoid run() { try { counter.increment(); Thread.sleep(1000); //Simulate we are doing something here threadMessage("" + counter.value()); } catch (InterruptedException e) { e.printStackTrace(); } } }
ThreadInterferenceExample.java publicclass ThreadInterferenceExample { publicstaticvoid main(String[] args) { ThreadInterference test = new ThreadInterference(); Thread t1 = new Thread(test); t1.start(); Thread t2 = new Thread(test); t2.start(); } } Here, we expected that: Thread t1 should start Counter object with 0, then increase to 1. Thread t2 should start after that, increase Counter from 1 to 2.
Actual Output Thread-2: 2 Thread-1: 2 Thread t1 result is lost, overwritten by Thread t2.
Thread Synchronization (cont.) Java uses monitors for thread synchronization The sychronized keyword Every synchronized method of an object has a monitor One thread inside a synchronized method at a time All other threads are blocked until synchronized method finishes Next highest priority thread runs when method finishes
Same monitor. Same monitor. Thread Synchronization (cont.) Each object instance has a “monitor”: It is combination of general monitor + a single condition variable. Classes are objects (Class class). So each class has a monitor, too. Ownership of instance monitor: synchronized void f() { /* owned */ } void f() { synchronized (this) { /* owned */ } } Ownership of class monitor: static synchronized void f() { /* owned */ } void f() { synchronized (this.getClass()) {/* owned */ } }
ThreadInterference.java (fix bug) publicclass ThreadInterference extends Thread { private Counter counter = new Counter(); staticvoid threadMessage(String message) { String threadName = Thread.currentThread().getName(); System.out.format("%s: %s%n", threadName, message); } @Override publicvoid run() { synchronized (counter) { try { counter.increment(); Thread.sleep(1000); //Simulate we are doing something here threadMessage("" + counter.value()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Actual Output Thread-2: 1 Thread-1: 2 Result now as now correct as we expected.
Practice: Thread Synchronization The bank in our model is actually a computer that performs operations on the account, and the account is stored separately. Each clerk can communicate directly with the bank. We'll be defining four classes that we will use in our program to model banking operations: A Bank class to represent the bank computer. An Account class to represent the account at the bank. A Transaction class to represent a transaction on the account ¡ª a debit or a credit for instance. A Clerk class to represent a bank clerk.