840 likes | 2.05k Vues
Threads in Java. Two ways to start a thread implement the Runnable Interface Extend Thread. Runnable Interface. public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } … }
E N D
Threads in Java • Two ways to start a thread • implement the Runnable Interface • Extend Thread
Runnable Interface public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } … } public static void main(String args[]) { HelloRunnable hr = new HelloRunnable(); Thread t = new Thread(hr); t.start(); }
Extending the Thread Class public class HelloThread extends Thread { public void run() { System.out.println(“Hello thread!"); } } public static void main(String args[]) { HelloThread ht = new HelloThread(); ht.start(); }
Threads in Java • How often does each thread run? Does each thread get the same share of time to run? • Can specific threads sleep for specific intervals? • How do threads wakeup? • How do threads wakeup based on specific conditions (change in state of the object)?
Threads • Thread.sleep(milliseconds) • The sleep method puts the current thread to sleep for a given number of milliseconds. • The thread scheduler runs each thread for a short amount of time, called a time slice.
Terminating a thread • A thread terminates when run method terminates. • May need to explicitly stop a thread • when a pool of threads is working on a problem • one of the thread finishes, rest need to stop • stop() method on the Thread class • deprecated, has side effects. Examples? • t.interrupt() • sets a boolean flag • thread should do the necessary cleanup
Pool of threads • The cost of creating threads is minimized. • Thread pools are particularly important for server programs • database and web servers, that repeatedly execute requests from multiple clients. • Rather than spawning a new thread for each request, the requests are implemented as runnable objects and submitted to a thread pool.
Thread: check if it is interrupted public void run() { for (int i = 1; i <= REPETITIONS && !Thread.interrupted(); i++) { Do work } Clean up } What if the thread is sleeping?
InterruptedException: summary • When a sleeping thread is interrupted, an InterruptedException is generated. • You need to catch that exception in your run method and terminate the thread.
Summary: Thread’s run() method public void run() { try { // Task statements } catch (InterruptedException exception) { // … } Clean up, if necessary }
Race conditions • When threads share access to a common object, they can conflict with each other. • A race condition occurs if the effect of multiple threads on shared data depends on the order in which the threads are scheduled. • Use synchronized keyword to ensure that only one thread can enter a method at a time • public synchronized addEntryToBuffer(…);
Synchronized class • Write a Java class Counter with three methods • increment • decrement • returnValue • The class should have a private data member • int counter
Race condition Example public class SyncCounter { private int counter = 0; // declare INCR as a static final int value public synchronized void increment() { c = c + INCR; } public synchronized void decrement() { c = c – INCR; } public int returnValue() { return c; } }
Classical Thread Synchronization • Lock/Condition classes were added from Java 1.5 • Every Java object has one built-in lock and one built-in condition variable. • To acquire the lock, you call a synchronized method . • public synchronized void addPrime() • When a thread calls a synchronized method on an object, it owns the lock of that object until it returns from the method and thereby unlocks the object. • When an object is locked by one thread, no other thread can enter a synchronized method for that object. • When another thread makes a call to a synchronized method for that object, the other thread is automatically deactivated, and it needs to wait until the first thread has unlocked the object again.
wait() and notify() • If you call x.wait(), the current thread is added to the set of threads that is waiting for the condition of the object x. • Most commonly, you will call wait(), which makes the current thread wait on this. public synchronized void checkPrime(…) throws InterruptedException { while (CONDITION) wait(); . . . } • The call notifyAll() unblocks all threads that are waiting for this public synchronized void addPrime() { notifyAll(); }
Create a Server Socket ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(5678); } catch (IOException e) { // handle the exception System.err.println("Could not listen on port: 5678."); System.exit(1); } finally { // close all resources claimed in the try clause }
Server: accept connections Socket handle2Client = null; try { handle2Client = serverSocket.accept(); } catch (IOException e) { // handle the exceptions } finally { // handle the finally clause }
Server: accept connections • handle2Client.getOutputStream() • handle2Client.getInputStream() • These two calls can be used to read and write to the socket. • You need to use Streams to read and write to these Sockets
Server Side Sockets • ServerSocket is a java.net class • Accept method waits until a client starts up and requests a connection on the host and port • When a connection is requested and successfully established, the accept method returns a new Socket object which is bound to the same local port and has it's remote address and remote port set to that of the client. • The server can communicate with the client over this new Socket and continue to listen for client connection requests on the original ServerSocket
Client Side Socket Socket clSocket = null; PrintWriter out = null; BufferedReader in = null; // obtain a client socket clSocket = new Socket(“bingsuns", 5678); // create the in and out streams out = new PrintWriter(clSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(clSocket.getInputStream()));
Client Side Socket (2) // reading from the standard input BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String fromServer = in.readLine(); String fromUser; // In a loop, do the following // read from the Server till the string is not null // if the server string says “bye”, quit the loop // read from the System.in the user’s response // send it to the server
Client Side Socket (3) while (CONDITION)) { // read from Socket’s Input Stream System.out.println("Server: " + fromServer); if (fromServer.equals("Bye.")) break; fromUser = READ FROM STDIN if (fromUser != null) { System.out.println("Client: " + fromUser); WRITE THE STRING TO THE SOCKET } }
Server Handler public class ServerHandler implements Runnable { private Socket socket; // private BufferedReader in; private PrintWriter out; public ServerHandler(Socket socket) throws IOException { // initialize the socket and streams } public void run() { // use the while loop we discussed in the previous slides } }
Multi-threaded Server try { // Create a Server socket for port 5678 while(true) { //Accept Connections on the Server Socket // Create a new instance of ServerHandler, pass it the new socket // Create a new Thread instance, pass it the handler, and call start on it } } catch(IOException ioe) { // handle the exception } finally { try { serverSocket.close(); } catch(IOException ioe) { // handle the exception } }
Multi-threaded Server try { serverSocket = new ServerSocket(5678); while(true) { socket = serverSocket.accept(); ServerHandler handler = new ServerHandler(socket); (new Thread(handler)).start(); } } catch(IOException ioe) { // handle the exception } finally { try { serverSocket.close(); } catch(IOException ioe) { // handle the exception } }