network programming - rmit...
Post on 30-Mar-2018
238 Views
Preview:
TRANSCRIPT
2NetProg 6 2
Threads
• Recall from last week– Every line of Java code is part of
a thread
– There can be one or more threads running in parallel
– Each thread has its own program counter (pointing to the current instruction being executed)
– All threads in a process share the execution environment
• Advantages of threads– Simpler program design
– More responsive programs
• Disadvantages– Context switching overhead
– Increased resource consumption
Concurrency and parallelism
Image source:http://www.nyu.edu/classes/jcf/g22.3033-007_sp01/handouts/g22_3033_h52.htm
3NetProg 6 3
Multithreading
• Operating system support for multithreading
– Simplifies the application code
– Allows more complex program execution
• Different threads may share a single CPU
– Threads can
• be interrupted to allow another thread to run (preemptive
scheduling)
• voluntarily give up control (e.g. when waiting for data from a socket)
• Different threads can run on different cores of a CPU
– Allows faster execution
Image source: http://blog.takipi.com/java-thread-magic-tricks/
4
Thread Risks
• Safety – Threads need sufficient synchronization, because
• The ordering of operations is unpredictable: the compiler, processor and runtime can reorder and time actions as they see fit (as long as it does not affect the result within the thread)
• Threads can access and modify variables that other threads are using
• Liveness– A thread should not get into a state that it cannot
make forward progress
• Performance– Runtime overhead (e.g. context switching, scheduling)
– Synchronization costs (e.g. data sharing, inhibited compiler optimization)
5NetProg 6 5
Thread Programming
• Most commonly called Concurrent Programming
• Basic issue: Data can be accessed by multiple threads simultaneously
• Aim: Protecting the data from uncontrolled concurrent access
• Basic solutions:– Thread confinement: don’t share state variables across threads
– Make state variables immutable
– Use synchronization when accessing state variables
• Thread safety: correct program operation (conforms with the specification)
Image source: http://blog.takipi.com/java-thread-magic-tricks/
6NetProg 6 6
Threads and Communications
• Rationale– Time lag between starting to listen to input and data actually
arriving
– Blocking while waiting for input suspends a whole (single threaded) program
• Maintaining control while waiting for input– Option 1: Synchronous communication
• Reader loops asking if data has arrived (e.g. available() )
– Option 2: Asynchronous communication• Callback: create a function to be invoked when data has arrived,
and register the function with the operating system
• Using multiple threads – Allows the blocking of one thread while other threads are running
– In general, threads of a task can execute at different speeds
7NetProg 6 7
Thread Lifecycle
• Thread attributes– ID, Name, Priority,
State
• Enum Thread.State
– NEW: the thread has not yet started
– RUNNABLE: thread executing in the JVM
– BLOCKED: waiting for the availability of an event or a resource
– WAITING: waiting indefinitely for another thread to perform a particular action
– TIMED_WAITING: similar to WAITING but time is limited
– TERMINATED
Image source: http://www.c-jump.com/bcc/c257c/Week13/Week13.html
8NetProg 6 8
Main Thread Methods
Getting information about a thread
• currentThread() Returns a reference to the current thread
• getId() getName() getPriority() getState() return the ID, name, priority and state of the current thread
• toString() returns a string representation of the current thread
Setting thread parameters• setName() setPriority()
• setDaemon(boolean on) marks this thread as daemon or user thread
Execution control
• start() the thread begins execution, the JVM calls the run method of this thread
• run() the Runnable object’s run method is called
• sleep(long millisec) puts the current thread to sleep
• yield() indicates that the current thread is willing to yield its current use of a processor
9NetProg 6 9
Multiple Threads -Code Example
public class Calculator implements Runnable {private int number;
public Calculator(int number) {this.number = number;
}
public void run() {for (int i = 1; i <= 10; i++) {
System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(), number, i, i * number);
}}
}
class Main {public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {Calculator calculator = new Calculator(i);Thread thread = new Thread(calculator);thread.start();
}}
}
10NetProg 6 10
Code Example - Thread States
Main : Status of Thread 0 : NEW
Main : Status of Thread 1 : NEW
Main : Status of Thread 2 : NEW
Main : Status of Thread 3 : NEW
Main : Status of Thread 4 : NEW
Main : Status of Thread 5 : NEW
Main : Status of Thread 6 : NEW
Main : Status of Thread 7 : NEW
Main : Status of Thread 8 : NEW
Main : Status of Thread 9 : NEW
Main : Id 9 - Thread 0
Main : Priority: 10
Main : Old State: NEW
Main : New State: RUNNABLE
Main : ************************************
Main : Id 10 - Thread 1
Main : Priority: 1
Main : Old State: NEW
Main : New State: BLOCKED
Main : ************************************
…
…
Main : Id 18 - Thread 9
Main : Priority: 1
Main : Old State: BLOCKED
Main : New State: RUNNABLE
Main : ************************************
Main : Id 18 - Thread 9
Main : Priority: 1
Main : Old State: RUNNABLE
Main : New State: TERMINATED
Main : ************************************
Main : Id 16 - Thread 7
Main : Priority: 1
Main : Old State: BLOCKED
Main : New State: RUNNABLE
Main : ************************************
Main : Id 16 - Thread 7
Main : Priority: 1
Main : Old State: RUNNABLE
Main : New State: TERMINATED
Main : ************************************
…
Code to Print the Thread Statesimport java.io.*;
import java.lang.*;
public class Calculator_info implements Runnable {
private int number;
public Calculator_info(int number) {
this.number = number;
}
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.printf("%s: %d * %d = %d\n",
Thread.currentThread().getName(), number, i, i * number);
}
}
}
class Main_1 {
public static void main(String[] args) {
Thread threads[]=new Thread[10];
Thread.State status[]=new Thread.State[10];
for (int i = 0; i < 10; i++) {
threads[i]=new Thread(new Calculator_info(i));
if ((i%2)==0){
threads[i].setPriority(
Thread.MAX_PRIORITY);
} else {
threads[i].setPriority(
Thread.MIN_PRIORITY);
}
threads[i].setName("Thread "+i);
}
1/2
try {FileWriter file = new FileWriter("log.txt");PrintWriter pw = new PrintWriter(file);for (int i=0; i<10; i++) {
pw.println("Main : Status of Thread " + i + " : " +threads[i].getState());
status[i] = threads[i].getState();}
for (int i=0; i<10; i++){threads[i].start();
}boolean finish=false;while (!finish) {
for (int i=0; i<10; i++){if (threads[i].getState()!=status[i]) {
writeThreadInfo(pw,threads[i],status[i]);status[i]=threads[i].getState();
}}finish=true;for (int i=0; i<10; i++){
finish=finish &&
(threads[i].getState()==java.lang.Thread.State.TERMINATED);}
}pw.close();
} catch(IOException e){}}private static void writeThreadInfo(PrintWriter pw,
Thread thread, java.lang.Thread.State state) {pw.printf("Main : Id %d - %s\n",
thread.getId(),thread.getName());pw.printf("Main : Priority: %d\n",thread.getPriority());pw.printf("Main : Old State: %s\n",state);pw.printf("Main : New State: %s\n",thread.getState());pw.printf("Main : ************************************\n");
}}
2/2
NetProg 6 11
12NetProg 6 12
Returning Information from a
Thread (1)
• The run() and start() methods do not return anything
• Solution: Using accessor (getter) methods
Steps
– Store the result in a field private to the thread
– Invoke the getter method
• Key point: The thread’s run method has to finish with the data before the accessor method is invoked
13NetProg 6 13
Returning Information from a
Thread (2)• There is no guarantee that one thread will be
faster/slower than another– If you call the getter method too early, the result may not be
ready
• Polling– The getter method returns a flag value (or throws an exception) if
the result is not ready yet
– Problem: inefficient, repeatedly calls the getter method• Even bigger problem: The main program usually has higher priority
and may not allow the thread to run at all
• Callbacks– When the thread finishes, it invokes a method in the main class
• The last step in the run method is invoking a method in the main program with the result
Main program Thread
Start the
thread
Callback
14NetProg 6 14
Callback Example– Code Excerptpublic class CallbackDigest implements Runnable {
private String filename;public CallbackDigest(String filename) {
this.filename = filename;}@Overridepublic void run() {
try {// Calculate the digestbyte[] digest = sha.digest();CallbackDigestUserInterface.receiveDigest(digest, filename);
} catch (IOException ex) {System.err.println(ex);
} catch (NoSuchAlgorithmException ex) {System.err.println(ex);
}}
}
public class CallbackDigestUserInterface {
public static void receiveDigest(byte[] digest, String name) {StringBuilder result = new StringBuilder(name);result.append(": ");result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);
}public static void main(String[] args) {
for (String filename : args) {CallbackDigest cb = new CallbackDigest(filename);Thread t = new Thread(cb);t.start();
}}
}
Thread
Main program
Callback
For the full example, see the textbook Java Network Programming
15NetProg 6 15
Thread Cooperation Issues
• Thread interferenceIf the following code is accessed by
two threads at the same time, the value of c will depend on the interleaving of the two threads
class Counter {private int c = 0;
public void increment() {c = c + 1;
}
public void decrement() {c = c -1 ;
}
public int value() {return c;
}}
• Memory consistency errorsDifferent threads have different views
of the same data
Example: Lost update
• Thread 1 reads c
• Thread 2 reads c
• Thread 1 increments the retrieved value (result is 1)
• Thread 2 decrements the retrieved value (result is -1)
• Thread 1 stores its value c = 1
• Thread 2 stores its value c = -1
Thread_1’s result has been lost
16NetProg 6 16
Race Conditions
• Definition: The correctness of a computation depends on the timing or interleaving of multiple threads
• Example: Lazy initialization– Initialization of a variable is often postponed until the variable is
used
– If two threads are using the same variable (e.g. a counter), multiple objects can be created instead one – each thread may create an object
• Java provides several methods to avoid race conditions– Synchronized execution
– Using the Volatile keyword
– Locks
– Atomic variables
We look at some of them in this lecture
17NetProg 6 17
Thread Safety
• Levels: thread safe, conditionally safe, not thread safe
• Thread-safe objects– Immutable objects by default
• E.g. read-only and final variables
– Local variables
• Volatile keyword– Guarantees visibility across threads
public volatile int counter = 0;
• Data is always read from memory, not from CPU cache
• The reading and writing instructions of volatile data cannot be reordered by the JVM (e.g. for performance reasons)
• More expensive read and write operations
• Need caution– Static variables (need a lot of caution!)
Code can be executed and shared in multithread environment and will behave as expected (no race conditions)
18NetProg 6 18
Resource Sharing Issues
• The scheduling of threads is unpredictable
• If a shared resource is used by many simultaneously, the result can be confusingE.g. lines (or even items) from different threads can get mixed up in
a printout
• Exclusive access needs to be granted to certain resources (e.g. printers), so that no other thread can jump in
Image source: http://blog.takipi.com/5-things-you-didnt-know-about-synchronization-in-java-and-scala/
19NetProg 6 19
Synchronization
• You can mark a group of statements to be executed without interruption
• It is called synchronization, and it works by locking the object for exclusive use
– Synchronization works only in the same JVM
• Synchronized methodpublic synchronized void increment() {
c = c + 1;}
The method has to complete before another thread can access c . Thread_1’s update will not be lost here
• Synchronized blockpublic void increment() {synchronized(this){
c = c + 1;}
}
• Unsynchronized threads’ operation sequences– are not affected
– have to happen either before or after the synchronized operations take place
20NetProg 6 20
Deadlocks
• If two threads want to access the same resources, deadlock can occur.E.g. Thread 1 has got hold of
B and wants to access A, while Thread 2 has got A and wants to access B.
• Deadlocks – can occur intermittently,
even between the same threads
– usually depend on timing
– can be hard to detect
T1
A
B
Synchronized
on B
T2
Wants to
access A
Wants to
access B
Synchronized
on A
21
Using Synchronization
• Synchronization and locks– Synchronizing a method locks the method
• Static methods lock the class
– Synchronizing a block needs an object to lock• It can be an arbitrary object not used for anything else
E.g. synchronized(this){}
• Synchronization should be used sparingly– It reduces performance
– It can result in a deadlock
• Synchronize only at the lowest level and only the code that really needs it
• To ensure that all threads see the most up-to-date values, the reading and writing threads must synchronize on a common lock
22
Secure Sharing of Objects
• Thread Confinement (no sharing)– Ad-hoc approach: leaves it to the implementation
– Thread-local usage: all variables can be accessed through local variables
– ThreadLocal : Each thread has its own, independently initialized copy of the variable. They are typically private static fields
• Safe publication (sharing)– Synchronized access in both the publishing and the
consuming thread
– Reference to the object and the object’s state must be made visible to other threads at the same time
23NetProg 6 23
Thread Scheduling (1)
• Priorities
– A thread with higher priority gets preference when executed
– A thread’s initial priority is the same as that of its creator
thread
public static final int MIN_PRIORITY
public static final int NORM_PRIORITY
public static final int MAX_PRIORITY
– Interpretation of thread priorities varies between systems
– Thread priority may not indicate share of CPU
Image source: http://www.javamex.com/tutorials/threads/priority_what.shtml
24NetProg 6 24
Thread Scheduling (2)
• Preemption– A running lower priority thread can be interrupted when a higher priority
thread wants to run
• Starvation– A thread does not get (enough) CPU time
– Operating systems usually manipulate thread priorities to avoid starvation
• Changing priorities from the application – It is a hint to the system
– The effect is hard to predict (it depends on the whole system - “OS knows best”)
Image source: http://blog.takipi.com/java-thread-magic-tricks/
25NetProg 6 25
Giving up Control• Blocking
– Waiting for in I/O operation to complete
– Executing a synchronized block
• yield()
– Indicates to the JVM that another thread can run
– The JVM may ignore this hint• The call has minimal effect if no need to yield
• wait(long timeout)
– Waits up to timeout or until another thread sends a notify() signal
– Keeps all its resources (others have to wait for those resources)
• sleep(long millisec)
– Forces the thread to pause, regardless of any threads waiting or not
– The sleeping time may be
• longer, if the JVM is busy doing other things
• shorter if an event or another thread wakes it up (e.g. by sending an interrupt)
– The thread still keeps all its resources
– Avoid using it
• in a synchronized block – can cause a deadlock or long wait
• to wait for an event in another thread – lazy solution, use wait() and notify() instead
26NetProg 6 26
Stopping a Thread
• Once a thread has started, nothing can (safely) stop it, except the thread itself. At most, the thread can be asked to stop itself (by getting interrupted). – An interrupted thread may not immediately stop what it is doing.
Threads may even ignore an interruption request (but that may compromise responsiveness).
• Stopping a thread is a two-step procedure– Design the thread to act on interruption
– Interrupt the thread. It means sending a stop signal to the thread
• interrupt() interrupt this thread
• isInterrupted() tests if this thread has been interrupted
• join() waits for this thread to die
27NetProg 6 27
Interrupting a Thread
• Cooperative mechanism– A signal is delivered to the thread
– The thread stops at the next available opportunity
• A thread can check for interruption regularly– The isInterrupted() method will return true if
interrupted (it leaves the interrupted status unchanged)
– If the thread is in a blocking method, it may take time until it can perform the check
– Blocking methods that support interruption usually throw an exception (InterruptedException)
28
Interruption Code Excerpt (1)
• Thread to be stoppedpublic class myTask extends Thread{
public void run() {
// Do something here
if (isInterrupted()) { // Testing if the thread has been interrupted
// The interrupted status of the thread is unaffectedSystem.out.printf("Interrupted");
return;
}
// Continue normally
}
}
• Main classpublic class Main {
public static void main(String[] args) {
Thread task=new myTask();
task.start();
Thread.sleep(5000); // Do something here
task.interrupt();
...
29
Interruption Code Excerpt (2)
Propagating interruption– Thread to be stopped
public class myTask extends Thread{
public void run() {
try{subTask();
} catch (InterruptedException e) {
System.out.printf("Interrupted“,
Thread.currentThread().getName());
return;
}
// Continue normally
...
private void subTask() throws InterruptedException {
// Do something here
if (Thread.interrupted()) { // Testing if the thread has been interrupted
// The interrupted status of the thread is clearedthrow new InterruptedException();
}
...
– Main classSame as on the previous slide
30NetProg 6 30
Finishing a Thread
• Method 1: join(long milliseconds)
– The invoking thread blocks and waits for another thread (whose method is invoked) to finish
– Can be used for getting the results from another thread
– It is a final method (you cannot override it)
• Method 2: Return from the run() method
– Often used in networking applications
31
Code Excerpt
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(myType1,“Type 1");
Thread thread2 = new Thread(myType2,“Type 2");
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
...
32NetProg 6 32
Reentrancy
• Reentrant code: can be interrupted in the middle of execution and safely re-entered before the previous invocation completes
• Similar to thread safety, but not the same– Reentrant code can achieve thread safety (by observing the respective
rules)
– Thread safe code is not necessarily reentrant
– They still use similar (but not the same) tools (e.g. locks)
• Rules– Reentrant code may not
• use any static or global non-constant data
• call non-reentrant programs, methods
• modify itself
• Examples for reentrant code– Any recursive function
– Interrupt handling
33NetProg 6 33
Thread Groups
• Connect several threads together
• Can be used for handling multiple threads jointly
• You can – list active group members (enumerate() list())
– set limits for them (setMaxPriority())
• Some methods are similar to Thread methods, (e.g. interrupt() setDaemon()) but many are missing (e.g. start() sleep())
• Normally, a thread is in the same group as the main thread of the application
• Example: use in communication applications– You want to stop input and output communication
simultaneously
top related