Lecture 4 Threads and Networking in Java TDDC32 Lecture notes in Design and Implementation of a Software Module in Java 23 January 2013 Tommy Färnqvist, IDA, Linköping University 4.1 Lecture Topics Contents 1 2 Threads 1.1 Introduction . . . . . . 1.2 Thread Programming . 1.3 The Life of a Thread . 1.4 Thread Synchronization . . . . 1 1 2 4 8 Networking 2.1 The Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Network Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 12 13 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Threads 1.1 Introduction Introduction to Threads in Java • In state-of-the art software, a program can be composed of multiple independent flows of control. • A flow of control is more commonly referred to as a process or thread. • In most of the Java programs that you’ve written (probably) there was a single flow of control. Most console-based programs begin with the first statement of the method main() and work forward to the last statement of the method main(). Flow of control is often temporarily passed to other methods through invocations, but the control returned to main() after their completion. • Programs with a single control flow are known as sequential processes. 4.3 Introduction to Threads in Java (cont.) • Java supports the creation of programs with concurrent flows of control. These independent flows of control are called threads. • Threads run within a program and make use of that program’s resources in their execution. For this reason threads are also called lightweight processes (LWP). • The ability to run more than one process simultaneously is an important characteristic of a modern OS such as Linux/Unix and Windows. 4.4 Typical Multithreaded Applications • Used to improve the performance of applications which require extensive I/O operations. • Useful in improving the responsiveness of GUI-based applications. • Used when two or more clients need to run server-based applications simultaneously. 4.5 1 1.2 Thread Programming Java Classes and Threads • Java has several classes that support the creation and scheduling of threads. • The two basic ways of creating threads in Java are: – extending the Thread class – or implementing the Runnable interface. – (Both are found in package java.lang. Thread actually implements Runnable.) 4.6 The Java Thread Class 4.7 Java Classes and Threads (cont.) • The following two simple examples, illustrate the differences in creating threads using these two different techniques. • In the example, three threads are created, – one that prints the character ’A’ twenty times, – one that prints the character ’B’ twenty times, and – a third thread that prints the integer numbers from 1 to 20. • The first program is an example of extending the Thread class. The second program is an example of using the Runnable interface. – This latter technique is the more common and preferred technique. 4.8 //Class to generate threads by extending the Thread class public class TestThread { // Main method public static void main(String[] args) { // Create threads PrintChar printA = new PrintChar(’a’, 20); PrintChar printB = new PrintChar(’b’, 20); PrintNum print20 = new PrintNum(20); // Start threads print20.start(); printA.start(); printB.start(); } 2 } // The thread class for printing a specified character // a specified number of times class PrintChar extends Thread { private char charToPrint; // The character to print private int times; // The times to repeat // Construct a thread with specified character // and number of times to print the character public PrintChar(char c, int t) { charToPrint = c; times = t; } 4.9 // Override the run() method to tell the system what the thread will do public void run() { for (int i = 0; i < times; i++) System.out.print(charToPrint); } } // The thread class for printing number from 1 to n for a given n class PrintNum extends Thread { private int lastNum; // Construct a thread for print 1, 2, ... i public PrintNum(int n) { lastNum = n; } // Tell the thread how to run public void run() { for (int i = 1; i <= lastNum; i++) System.out.print(" " + i); } } //end class TestThread 4.10 //Class to generate threads by implementing the Runnable interface public class TestRunnable { // Create threads Thread printA = new Thread(new PrintChar(’a’, 20)); Thread printB = new Thread(new PrintChar(’b’, 20)); Thread print20 = new Thread(new PrintNum(20)); public static void main(String[] args) { new TestRunnable(); } public TestRunnable() { // Start threads print20.start(); printA.start(); printB.start(); } // The thread class for printing a specified character // a specified number of times class PrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The times to repeat // Construct a thread with specified character 3 // and number of times to print the character public PrintChar(char c, int t) { charToPrint = c; times = t; } 4.11 // Override the run() method to tell the system what the thread will do public void run() { for (int i = 0; i < times; i++) System.out.print(charToPrint); } } // The thread class for printing number from 1 to n for a given n class PrintNum implements Runnable { private int lastNum; // Construct a thread for print 1, 2, ... i public PrintNum(int n) { lastNum = n; } // Tell the thread how to run public void run() { for (int i = 1; i <= lastNum; i++) System.out.print(" " + i); } } } //end class TestRunnable 4.12 1.3 The Life of a Thread Life Cycle of a Thread • At any given point in time, a thread is said to be in one of several thread states as illustrated in the diagram below. 4.13 Life Cycle of a Thread (cont.) 4 4.14 Life Cycle of a Thread (cont.) 4.15 Life Cycle of a Thread (cont.) 5 4.16 Life Cycle of a Thread (cont.) 4.17 Life Cycle of a Thread (cont.) 6 4.18 Life Cycle of a Thread (cont.) 4.19 Summary of States In The Life Cycle of a Thread 7 4.20 Life Cycle of a Thread – A Slightly Different View • At any given point in time, a thread is said to be in one of several thread states as illustrated in the diagram below. 4.21 Thread Priorities • Every Java thread has a priority that helps the OS determine the order in which threads are scheduled. • Java priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). • Threads with a higher priority are more important to a program and should be allocated processor time before lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute. • By default, every thread is given priority NORM_PRIORITY (a constant of 5). Each new thread inherits the priority of the thread that created it. 1.4 4.22 Thread Synchronization Related and Synchronized Threads • The most complicated type of threaded application involves threads which interact with each other. – These are related synchronized threads (also referred to as cooperating threads). • Without synchronization when multiple threads share an object and that object is modified by one or more of the threads, indeterminate results may occur. This is known as a data race or race condition. • The following example illustrates a race condition. In this example, we simulate a steam boiler and the reading of its pressure. 8 4.23 // class to simulate a steam boiler to illustrate a race condition // in unsynchronized threads public class SteamBoiler1 { static int pressureGauge = 0; static final int safetyLimit = 50; public static void main(String [] args) { pressure1 []psi = new pressure1[10]; for (int i = 0; i < 10; i++) { psi[i] = new pressure1(); psi[i].start(); } //we now have 10 threads in execution to monitor the pressure try { for (int i = 0; i < 10; i++) psi[i].join(); //wait for the thread to finish } catch (Exception e) { } //do nothing System.out.println(); System.out.print("Gauge reads " + pressureGauge + ", the safe limit is " + safetyLimit); if (pressureGauge > safetyLimit) System.out.println("...B O O M ! ! !"); else System.out.println("...System OK!"); } } 4.24 //thread class to raise the pressure in the Boiler class pressure1 extends Thread { void RaisePressure() { if (SteamBoiler1.pressureGauge < SteamBoiler1.safetyLimit-15) { //wait briefly to simulate some calculations try {sleep(100); } catch (Exception e) { } SteamBoiler1.pressureGauge += 15; //raise the pressure 15 psi System.out.println("Thread " + this.getName() + " finds pressure within limits - increases pressure"); } else System.out.println("Thread" + this.getName() + " finds pressure too high - do nothing"); } public void run() { RaisePressure(); } //this thread is to raise the pressure } 4.25 Thread Synchronization • To prevent a race condition, access to the shared object must be properly synchronized. – Lost update problem: one thread is in the process of updating the shared value and another thread also attempts to update the value. – Even worse is when only part of the object is updated by each thread in which case part of the object reflects information from one thread while another part of the same object reflects information from another thread. • The problem can be solved by giving one thread at a time exclusive access to code that manipulates the shared object. During that time, other threads desiring to manipulate the object must be forced to wait. 4.26 9 Thread Synchronization (cont.) • When the thread with exclusive access to the object finishes manipulating the object, one of the blocked threads will be allowed to proceed and access the shared object. – The next selected thread will be based on some protocol. The most common of these is simply FCFS (priority-queue based). • In this fashion, each thread accessing the shared object excludes all other threads from accessing the object simultaneously. This is the process known as mutual exclusion. • Mutual exclusion allows the programmer to perform thread synchronization, which coordinates access to shared objects by concurrent threads. 4.27 Synchronization Techniques • There have been many different methods used to synchronize concurrent processes. Some of the more common ones are: – Test and Set Instructions. All general purpose processors now have this kind of instruction, and it is used to build higher-level synchronization constructs. Test and set does not block, that must be built on top of it. – p and v semaphores. Introduced by Dijkstra in the 1960’s and was the main synchronization primitive for a long time. Its easy to build semaphores from test and set instructions. Semaphores are low-level and can be hard for programmers to read and debug. The p is short for the Dutch words proberen te verlangen which means to “try to decrement” and the v stands for verhogen which means to increment. 4.28 Synchronization Techniques (cont.) – Read/write Locks. These are also commonly referred to as mutexes (although some people still use the term mutex to refer to a semaphore.) A lock provides a simple “turnstile”: only one thread at a time can be going through (executing in) a block protected by a lock. Again, it is easy to build a lock from semaphores. – Monitors. A monitor is a higher-level synchronization construct built out of a lock plus a variable that keeps track of some related condition, such as “the number of unconsumed bytes in the buffer”. It is easy to build monitors from read/write locks. A monitor defines several methods as a part of its protocol. Two of those predefined methods are wait() and notify(). 4.29 Types of Synchronization • There are two basic types of synchronization between threads: – Mutual exclusion is used to protect certain critical sections of code from being executed simultaneously by two or more threads. (Synchronization without cooperation.) – Signal-wait is used when one thread need to wait until another thread has completed some action before continuing. (Synchronization with cooperation.) • Java includes mechanisms for both types of synchronization. • All synchronization in Java is built around locks. Every Java object has an associated lock. Using appropriate syntax, you can specify that the lock for an object be locked when a method is invoked. Any further attempts to call a method for the locked object by other threads cause those threads to be blocked until the lock is unlocked. 4.30 Thread States With Synchronization 10 4.31 Deadlock • Deadlock will occur when a waiting thread (call it thread 1) cannot proceed because it is waiting (either directly or indirectly) for another thread (call it thread 2) to proceed, while simultaneously thread 2 cannot proceed because it is waiting (either directly or indirectly) for thread 1 to proceed. 4.32 Producer/Consumer Problem Threads Without Synchronization • In a producer/consumer relationship, the producer portion of an application generates data and stores it in a shared object, and the consumer portion of an application reads data from the shared object. – Common examples are print spooling, copying data onto CDs, etc. • In a multithreaded producer/consumer relationship, a producer thread generates data and places it in a shared object called a buffer. A consumer thread reads data from the buffer. • In lab 2, you will consider how logic errors can arise if we do not synchronize access among multiple threads manipulating shared data in this scenario. 4.33 Monitors and Monitor Locks • The way you will perform synchronization (in lab 2) is to use Java’s built-in monitors. Every object has a monitor. Strictly speaking, the monitor is not allocated unless it is used. • A monitor allows one thread at a time to execute inside a synchronized statement on the object. This is accomplished by acquiring a lock on the object when the program enters the synchronized statement. synchronized(object) { statements } // end synchronized statements – Where object is the object whose monitor lock will be acquired. • If there are several synchronized statements attempting to execute on an object at the same time, only one of them may be active on the object at once – all the other threads attempting to enter a synchronized statement on the same object are placed into the blocked state. 4.34 Mutual Exclusion Over a Block of Statements • When a synchronized statement finishes executing, the monitor lock on the object is released and the highest priority blocked thread attempting to enter a synchronized statement proceeds. • Applying mutual exclusion to a block of statements rather than to an entire class or an entire method is handled in much the same manner, by attaching the keyword synchronized before a block of code. • You must explicitly mention in parentheses the object whose lock must be acquired before the block can be entered. • The next page illustrates the steam boiler pressure gauge problem using a synchronized statement block to control the threads access to the pressure gauge. 4.35 11 //thread class to raise the pressure in the Boiler class syncPressure extends Thread { static Object O = new Object(); void RaisePressure() { synchronized(O) { if (syncSteamBoiler.pressureGauge < syncSteamBoiler.safetyLimit-15) { //wait briefly to simulate some calculations try {sleep(100); } catch (Exception e) { } syncSteamBoiler.pressureGauge += 15; //raise the pressure 15 psi System.out.println("Thread " + this.getName() + " finds pressure within limits - increases pressure"); } else System.out.println("Thread" + this.getName() + " finds pressure too high - do nothing"); } } public void run() { RaisePressure(); //this thread is to raise the pressure } } 4.36 Monitors and Monitor Locks (cont.) • Java also allows synchronized methods. A synchronized method is equivalent to a synchronized statement enclosing the entire body of a method. • If a thread obtains the monitor lock on an object and then discovers that it cannot continue with its task until some condition is satisfied, the thread can invoke Object method wait, releasing the monitor lock on the object. This will place the thread in the wait state. • When a thread executing a synchronized statement completes or satisfies the condition on which another thread may be waiting, it can invoke Object method notify to allow a waiting thread to transition to the blocked state again. • Caution: As with any multi-threaded application, care must be taken when using synchronization to achieve the desired effect and not introduce some serious defect in the application. 4.37 2 Networking 2.1 The Internet Technical Principles of the Internet • Communications systems such as the Internet are best described using layered models because of their complexity. • Every layer within the model has a certain task, and all layers together produce a particular communication service for the user. • The layers are arranged in hierarchical form. Layers lower in the hierarchy produce a service used by the higher layers. The uppermost layer finally combines all lower layer services and constitutes the interface for applications. • For the Internet, the so-called Internet reference model is used and is shown on the next slide. 4.38 Internet Reference Model 12 4.39 Internet Reference Model (cont.) • The Link Layer describes the possible sub-networks of the Internet and their medium access protocols. These are, for example, Ethernets, token rings, FDDI, or ISDN networks. To its upper layer, the link layer offers communication between two computers in the same sub-network as a service. • The Network Layer unites all the sub-networks to become the Internet. The service offered involves making communication possible between any two computers on the Internet. The network layer accesses the services of the link layer, in that a connection between two computers in different networks is put together for many small connections in the same network. 4.40 Internet Reference Model (cont.) • The Transport Layer oversees the connection of two (or more) processes between computers communicating with each other via the network layer. • The Application Layer makes application-specific services available for inter-process communication. These standardized services include e-mail, file transfer and the World Wide Web. • Within the layers, protocols are used for the production of a service. Protocols are instances which can be implemented either in hardware or software, and communicate with their partner instances in the same levels, but on other computers. It is only this cooperation that enables the service to be produced for the next level up. 4.41 Internet Reference Model (cont.) • The TCP/IP Protocol constitutes the core of Internet communication technology in the transport and network layers. • Every computer on the Internet always has an implementation of both protocols, TCP (Transmission Control Protocol) and IP (Internet Protocol). • The task of IP is to transfer data from one Internet computer (the sender) to another (the receiver). On this basis, TCP then organizes the communication between the two processes on these two computers. 4.42 2.2 Network Programming Networking • Java’s fundamental networking capabilities are declared by classes and interfaces of the java.net package, through which Java offers stream-based communications. • The classes and interfaces of java.net also offer packet-based communications for transmitting individual packets of information. This is most commonly used to transmit audio and video over the Internet. • We will focus on both sides of the client-server relationship. • The client requests that some action be performed, and the server performs the action and responds to the client. 13 4.43 java.net • “High-level” APIs – Implement commonly used protocols such as HTML, FTP, etc. • “Low-level” APIs – Socket-based communications ∗ Applications view networking as streams of data ∗ Connection-based protocol ∗ Uses TCP (Transmission Control Protocol) – Packet-based communications ∗ Individual packets transmitted ∗ Connectionless service ∗ Uses UDP (User Datagram Protocol) 4.44 Sockets • Java’s socket-based communications enable applications to view networking as if it were file I/O. In other words, a program can read from a socket or write to a socket as simply as reading from a file or writing to a file. • A socket is simply a software construct that represents one endpoint of a connection. • Stream sockets enable a process to establish a connection with another process. While the connection is in place, data flows between the processes in continuous streams. • Stream sockets provide a connection-oriented service. The protocol used for transmission is the popular TCP (Transmission Control Protocol). Provides reliable, in-order byte-stream service. 4.45 Sockets (cont.) • Datagram sockets transmit individual packets of information. This is typically not appropriate for use by everyday programmers because the transmission protocol is UDP (User Datagram Protocol). • UDP provides a connectionless service. A connectionless service does not guarantee that packets arrive at the destination in any particular order. • With UDP, packets can be lost or duplicated. Significant extra programming is required on the programmer’s part to deal with these problems. • UDP is most appropriate for network applications that do not require the error checking and reliability of TCP. 4.46 Sockets (cont.) • • • • Under UDP there is no “connection” between the server and the client. There is no “handshaking”. The sender explicitly attaches the IP address and port of the destination to each packet. The server must extract the IP address and port of the sender from the received packet. From an application viewpoint, UDP provides unreliable transfer of groups of bytes (“datagrams”) between client and server. 4.47 Socket Programming with TCP • Server process must first be running (must have created a socket). Recall that TCP is not connectionless. • Client contacts the server by creating client-local socket specifying IP address and port number of server process. Client TCP establishes connection to server TCP. • When contacted by client, server TCP creates a new socket for server process to communicate with client. – Allows server to talk with multiple clients – Source port numbers used to distinguish clients • From application viewpoint: TCP provides reliable, in-order transfer of bytes (“pipe”) between client and server. 4.48 14 Establishing a Simple Server Using Stream Sockets • Five steps to create a simple stream server in Java: 1. ServerSocket object. Registers an available port and a maximum number of clients. 2. Each client connection handled with a Socket object. Server blocks until client connects. 3. Sending and receiving data – OutputStream to send and InputStream to receive data. – Methods getInputStream and getOutputStream on Socket object. 4. Process phase. Server and client communicate via streams. 5. Close streams and connections. 4.49 Establishing a Simple Client Using Stream Sockets • Four steps to create a simple stream client in Java: 1. Create a Socket object for the client. 2. Obtains Socket’s InputStream and OutputStream. 3. Process information communicated. 4. Close streams and Socket. 4.50 Example: client/server socket interaction via TCP 4.51 Example: Java server using TCP import java.io.*; import java.net.*; class TCPServer { public static void main(String args[]) throws Exception { String clientSentence; String capitalizedSentence; // create welcoming socket at port 6789 ServerSocket welcomeSocket = new ServerSocket(6789); while (true) { // block on welcoming socket for contact by a client Socket connectionSocket = welcomeSocket.accept(); // create input stream attached to socket BufferedReader inFromClient = new BufferedReader( 15 new InputStreamReader(connectionSocket.getInputStream())); // create output stream attached to socket DataOutputStream outToClient = new DataOutputStream( connectionSocket.getOutputStream()); 4.52 Example: Java server using TCP (cont.) // read in line from the socket clientSentence = inFromClient.readLine(); // process capitalizedSentence = clientSentence.toUpperCase() + ’\n’; // write out line to socket outToClient.writeBytes(capitalizedSentence); } } } 4.53 Example: Java client using TCP //simple client application using TCP import java.io.*; import java.net.*; class TCPClient { public static void main(String args[]) throws Exception { String sentence; String modifiedSentence; // create input stream BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in)); // create client socket and connect to server Socket clientSocket = new Socket("remote-und.ida.liu.se", 6789); // create output stream attached to socket DataOutputStream outToServer = new DataOutputStream( clientSocket.getOutputStream()); // create input stream attached to socket BufferedReader inFromServer = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); 4.54 Example: Java client using TCP (cont.) sentence = inFromUser.readLine(); // send line to server outToServer.writeBytes(sentence + ’\n’); // read line from server modifiedSentence = inFromServer.readLine(); System.out.println("[From server:] " + modifiedSentence); clientSocket.close(); } } 4.55 16 Voluntary Homework Problem Build a skip list for the elements 1, 3, 5, 7, 2, 4, 6, 8, inserted in that order. The results of the coin tosses are (H=head, T=tail) H, H, T, T, over and over again. 17 4.56