980 likes | 1k Views
Programming in Java. Thread, Network programming 蔡文能 交通大學資訊工程學系 tsaiwn@csie.nctu.edu.tw. Agenda. Threads and Multithreading Creating a Thread extending the Thread class implementing the Runnable interface Deadlock and Synchronization in Threads Network Programming example
E N D
Programming in Java Thread, Network programming 蔡文能 交通大學資訊工程學系 tsaiwn@csie.nctu.edu.tw
Agenda • Threads and Multithreading • Creating a Thread • extending the Thread class • implementing the Runnable interface • Deadlock and Synchronization in Threads • Network Programming example • Socket programming • Network Programming again • TCP/IP protocols • URL : read/write
Thread vs. Process • A thread (執行緒; 線程)is a single stream of execution within a process. • A process (行程; 執行中的程式)is a program executing in its own address space(位址空間, 例如 0 ~ 65535). • You have been using threads all along. • The main control or execution of all the programs up until • now were controlled by a single thread. • What we want to look at is mutlithreading or having multiple threads executing within the same program.
TestTea.java (1/3) //TestTea.java --- by tsaiwn@csie.nctu.edu.tw ///This program demostrates how to use Thread in Java. ///But there are two problems: ///(1) stop() is unsafe. This might crash the program.(多 Run 幾次試試) /// We should tell thread to die by using a flag instead of /// using stop( ) to kill the thread. ///(2)concurrent access to TestTea.n might cause synchronization problem. /// Codes access to the same variable should be monitored by using /// a synchronized block to mark as a Critical Section. To use Thread SAFELY, Please See TeaOK.Java
TestTea.java (2/3) public class TestTea { protected static long n = 0; public static void main(String[]x) throws Exception{ Tea t1 = new Tea(); Coffee t2 = new Coffee(); t1.start( ); t2.start( ); while(true){ Thread.sleep(13); if(n > 10){ t1.stop( ); t2.stop( ); break; } } // while System.out.println("Thank you and Bye!"); } }
TestTea.java (3/3) class Coffee extends Thread { public void run( ) { while(true){ System.out.println("Drink Coffee "+ ++TestTea.n); // yield( ); } } // run } class Tea extends Thread{ public void run( ){ while(true){ System.out.println("Drink Tea "+ ++TestTea.n); // yield( ); } } // run }
Multitasking and Multithreading • Multitasking: • - having more than one program working at what seems to be at the same time (running concurrently). • - The OS assigns the CPU to the different programs in a manner to give the impression of concurrency. • - There are two types of multitasking – • preemptive and cooperative multitasking. • Multithreading: • - extends the idea of multitasking by allowing individual programs to have what appears to be multiple tasks. • - Each task within the program is called a thread.
How to create Java Thread (1/2) • Java has multithreading built into it. • Java provides a Thread class for handling threads. • There are two ways to create Thread objects • - creating objects from subclasses of the Java Thread class • - implementing the Runnable interface for an object class ThreadX extends Thread { public void run( ) { //logic for the thread } } Thread ThreadSubclass ThreadX tx = new ThreadX( ); tx.start( );
How to create Java Thread (2/2) - implementing the Runnable interface for an object Runnable class RunnableY implementsRunnable { public void run ( ) { //logic for the thread } } implements SomeSubclass RunnableY ry = new RunnableY(); Thread ty = new Thread(ry); ty.start(); In both methods, the run( ) method should be implemented.
Thread Class • The Thread class is part of the java.lang package. • Using an object of this class, the corresponding thread can • be stopped, paused, and resumed. • There are many constructors and methods for this class, we • will look at a few of them: • - Thread( String n) - creates a new Thread with the name n. • - Thread( Runnable target) - creates a new Thread object. • - Thread( Threadgroup group, Runnable target) • This creates a new Thread object in the specified Threadgroup.
Methods in Thread Class instance methods: getPriority( ); setPriority( ); start( ); stop( ); (deprecated) run( ); isAlive( ); suspend( ); resume( ); join( ); static methods: activeCount(); currentThread(); sleep(); yield();
Creating Threads (1/4) • Creating a thread by subclassing the Thread class • This method will allow only five thread to be started in an • object. • public class SimpleThread extends Thread{ • private int countDown = 3; • private static int threadCount = 0; • private int threadNumber = ++threadCount; • public SimpleThread( ) { • System.out.println("Making" + threadNumber++); • }
Creating Threads (2/4) public void run( ) { while(true) { System.out.println("Thread " + threadNumber + " (" + countDown + ") "); if (--countDown == 0) return; } } public static void main(String[] args) { for (int i = 0; i < 5; i++) new SimpleThread( ).start( ); System.out.println("All Threads Started"); } }
Creating Threads (3/4) • One possible output of ‘SimpleThread’: • Making 1 All Threads Started • Making 2 Thread 2(3) • Making 3 Thread 2(2) • Making 4 Thread 6(3) • Making 5 Thread 3(2) • Thread 3(3) Thread 2(1) • Thread 4(3) Thread 6(2) • Thread 4(2) Thread 6(1) • Thread 4(1) Thread 3(1) • Thread 5(3) • Thread 5(2) • Thread 5(1)
2(3) 5(3) 6(3) 3(3) 4(3) 2(2) 5(2) 6(2) 4(2) 3(2) 6(1) 5(1) 4(1) 3(1) 2(1) Creating Threads (4/4) • One possible output of ‘SimpleThread’: Tmain T0 T1 T2 T3 T4 Making 1 Making 5 Making 2 Making 3 Making 4 All Thread started
Synchronization in Threads (1/5) • Synchronization is a mechanism to control the the • execution of different threads so that: • - when multiple threads access a shared variable, proper • execution can be assured. • Java has the synchronized keyword - this can be used to • identify a segment of code or method that should be • accessible to just a single thread at a time. • Before entering a synchronization region, a thread should obtain the semaphore associated with that region – if it is already taken, then the thread blocks (waits) until the semaphore is released.
Synchronization in Threads (2/5) • class Account{ • private int balance = 0; • synchronized void deposit(int amount) { • balance += amount; • } • } • class Customer extends Thread { • Account account; • Customer(Account account) { • this.account = account; • } • public void run() { • try { for (int i = 0; i < 10000; i++) • {account.deposit(10);} • }
Synchronization in Threads (3/5) • catch (Exception e) { • e.printStackTrace(); • } • } /* run */ • } /* Customer */ • public class BankDemo { • private final static int NUMCUSTOMER = 10; • public static void main(String args[ ]) { • //Create account • Account account = new Account(); • //Create and start customer threads • Customer customer[ ] = new Customer[NUMCUSTOMER]; • for (int i = 0; i < NUMCUSTOMER; i++) { • customer[i] = new Customer(account); • customer[i].start( ); • }
Synchronization in Threads (4/5) • //Wait for customer threads to complete • for (int i = 0; i < NUMCUSTOMER; i++) { • try { • customer[i].join( ); • } • catch (InterruptedException e) { • e.printStackTrace( ); • } • } • //Display account balance • System.out.println(account.getBalance( ) ); • } • }
Synchronization in Threads (5/5) • In Java, any object with one or more synchronized methods is a monitor. • When threads call a synchronized method, only one thread is let in at a time, the others wait in a queue. • In producer- consumer type applications, consumer threads might find that there is not enough elements to consume • It is the job of the monitor to ensure that the threads that are waiting for the producer are notified once the elements are produced.
Thread Communication (1/6) • A thread can temporarily release a lock so other threads can have an opportunity to execute a synchronized method. • It is because the Object class defined three methods that allow threads to communicate with each other. • - void wait( ) - causes the thread to wait until notified - this method • can only be called within a synchronized method. • - void wait(long msec) throws InterruptedException • - void wait(long msec, int nsec) throws InterruptedException • - void notify( ) - notifies a randomly selected thread waiting for a lock on this object - can only be called within a synchronized • method. • - void notifyall( ) - notifies all threads waiting for a lock on this object - can only be called within a synchronized method.
Thread Communication (2/6) • class Producer extends Thread { • Queue queue; • Producer (Queue queue) { • this.queue = queue; • } • public void run( ) { • int i = 0; • while(true) { • queue.add(i++); • } • } • }
Thread Communication (3/6) • class Consumer extends Thread { • String str; • Queue queue; • Consumer (String str, Queue queue) { • this.str = str; • this.queue = queue; • } • public void run( ) { • while(true) { • System.out.println(str + ":" + queue.remove( ) ); • } • } • }
Thread Communication (4/6) • class Queue { • private final static int SIZE = 10; • int array[ ] = new int[SIZE]; • int r = 0; • int w = 0; • int count = 0; • synchronized void add(int i) { • //wait while the queue is full • while (count == SIZE) { • try { • wait( ); • } • catch (InterruptedException ie) { • ie.printStackTrace( ); • System.exit(0); • }} /* add */
Thread Communication (5/6) • //Add data to array and adjust write pointer • array[w++] = i; • if (w >= SIZE) • w = 0; • //Increment count • ++count; • //Notify waiting threads • notifyAll( ); • } • synchronized int remove( ) { • //wait while the queue is empty • while (count == 0) { • try { wait( ); } • catch (InterruptedException ie) { • ie.printStackTrace( ); • System.exit(0);}}
Thread Communication (6/6) • //read data from array and adjust read pointer • int element = array[r++]; • if (r >= SIZE) • r = 0; • //Decrement count • --count; • //Notify waiting threads • notifyAll( ); return element; • }} • public class ProducerConsumer { • public static void main(String args[ ]) { • Queue queue = new Queue( ); • new Producer(queue).start( ); • new Consumer("ConsumerA", queue).start( ); • new Consumer("ConsumerB", queue).start( ); • new Consumer("ConsumerC", queue).start( );}}
Thread Lifecycle 藍色的是 deprecated Active sleep(time) Blocked wake up Born JVM yield( ) suspend() start( ) Runnable resume() stop( ) wait( ) stop( ) return( ) return( ) notify( ) Dead block on I/O I/O complete
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Wait/Notify Sequence Lock Object 3. produceResource() 1. synchronized(lock){ 4. synchronized(lock) { 2. lock.wait(); 5. lock.notify(); 9. consumeResource(); 6.} 10. } 7. Reacquire lock 8. Return from wait() Consumer Thread Producer Thread
Scheduling : preemptive vs. nonpreemptive • Thread scheduling is the mechanism used to determine how runnable threads are allocated CPU time • A thread-scheduling mechanism is either preemptive or nonpreemptive • Preemptive scheduling – the thread scheduler preempts (pauses) a running thread to allow different threads to execute • Nonpreemptive scheduling– the scheduler never interrupts a running thread • The nonpreemptive scheduler relies on the running thread to yield control of the CPU so that other threads may execute
Starvation • Nonpreemptive scheduler may cause starvation(runnable threads, ready to be executed, wait to be executed in the CPU a lot of time, maybe even forever) • Sometimes, starvation is also called livelock
Deadlock • Deadlock • Deadlock is an error that can be encountered in multithreads. • It occurs when two or more threads wait indefinitely for each other to relinquish locks. • - Assume that thread-1 holds a lock on object-1 and waits for a lock on object-2. Thread-2 holds a lock on object-2 and waits for a lock on object-1. • - Neither of these threads may proceed. Each waits forever for the other to relinquish the lock it needs.
Thread Priority • The priority values range from 1 to 10, in increasing priority
Thread Priority • Every thread has a priority • When a thread is created, it inherits the priority of the thread that created it • The priority can be adjusted subsequently using the setPriority() method • The priority of a thread may be obtained using getPriority() • Priority constants are defined: • MIN_PRIORITY=1 • MAX_PRIORITY=10 • NORM_PRIORITY=5
Socket Programming • A server runs on a computer. • It has a socket that is bound to a port number. • The client tries to rendezvous with the server. • On the server's machine and port. • The server accepts the connection. • Upon acceptance, the server gets a new socket bound to a different port.
Sever - client communication • A socket can be considered as a connection point. port1 portN SEVER: … ... Sockets(Ipc, Port’sM, port1) IP address IPs IP address IPc Socketc(Ips, Port1, port’M) … ... CLIENT: Port’1 Port’M
Reading from and Writing to a Socket • The client in a client-server architecture • Open a socket. • Open an input stream and output stream to the socket. • Read from and write to the stream according to the server's protocol. • Close the streams. • Close the socket. • Only step 3 differs from client to client, depending on the server.
import java.net.*; import java.io.*; public class EchoClient { public static void main(String[] args) throws IOException { Socket echoSocket = null; PrintWriter out = null; BufferedReader in = null; try { echoSocket = new Socket("taranis", 7); //1 out = new PrintWriter(echoSocket.getOutputStream(), true); //2 in = new BufferedReader( new InputStreamReader(echoSocket.getInputStream())); } catch (UnknownHostException e) { System.err.println("Don't know about host: taranis."); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for " + "the connection to: taranis."); System.exit(1); }
BufferedReader stdIn = new BufferedReader( new InputStreamReader(System.in)); String userInput; while ((userInput = stdIn.readLine()) != null) { //3 out.println(userInput); System.out.println("echo: " + in.readLine()); } out.close(); //4 in.close(); //4 stdIn.close(); echoSocket.close(); //5 } }
Writing the Server Side of a Socket • java.net.Socket for client side. • java.net.ServerSocket for server side. try { serverSocket = new ServerSocket(4444); } catch (IOException e) { System.out.println("Could not listen on port: 4444"); System.exit(-1); }
SocketclientSocket = null; try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.out.println("Accept failed: 4444"); System.exit(-1); } • The accept method waits until • A client starts up and requests a connection on the host and port of this server. • When a connection is established • the accept method returns a new Socket object which is bound to a new port.