250 likes | 538 Views
Practical Session 6. Multitasking vs. multithreading Threads Concurrency vs. Parallelism Java Threads Thread confinement Object/Class Immutability. Multitasking vs. Multithreading. Multitasking: Running more than one process on same processor.
E N D
Practical Session 6 Multitasking vs. multithreading Threads Concurrency vs. Parallelism Java Threads Thread confinement Object/Class Immutability
Multitasking vs. Multithreading • Multitasking: • Running more than one process on same processor. • Uses context switching between different processes: (context=CPU state=content of CPU registers + program counter) • Switching from process A to B: • Context of process A is stored. • Context of process B is restored. • Multithreading: • Running more than one thread under same process. • Has the ability of resource sharing – all threads can access all resources of a process.
Threads • Definition • A way to share a single CPU between multiple tasks. • Benefits • Allows maintaining responsiveness of an application. • HTTP Server waiting for requests • Enable cancellation of separate tasks • Some problems require parallelism • Google’s Map/Reduce • Allows monitoring status of a resource (data base) • Allows taking advantage of multiple processors
Concurrency vs. Parallelism • Concurrency: • Two tasks can start and compete for CPU resources • Two threads running on same processor • They “share” the processor. • Parallelism • Two tasks that run at the same time in parallel. • They do not compete on process time. • Threads are executing simultaneously
Concurrency vs. Parallelism CPU CPU1 CPU2
Java Threads • Done by implementing the interface java.lang.Runnable. • java.lang.Runnable • Allows any class that implements it to operate as a thread. • Requires one method to be implemented: • public void run() • Implementation: class <className> implements Runnable { public void run(){ //the “main” function of the thread } }
How to Run Threads • By implementing Runnable and wrapping it with a Threadinstance. • takes a single Runnable object and executes it in a separate thread. • It is activated by calling start() • calls the Runnable run() method. • By implementing Runnable and passing it to an Executor. • By extending the Thread class.
Wrapped by a Thread- Threads01.java • class SimpleRunnable implements Runnable { • private String name; • SimpleRunnable(String name) { • this.name = name; • } • //prints name three time waits 0.1 second between each print • public void run() { • for (int i = 0; i < 3; i++) { • System.out.println("RUNNABLE:" + this.name); • try { • Thread.sleep(100);//time in miliseconds • } catch (Exception e) { • e.printStackTrace(); • } • } • } • }
public class Threads01 { • //creates to simeRunnable threads and starts them • public static void main(String[] a) { • SimpleRunnable r1 = new SimpleRunnable("r1"); • Thread t1 = new Thread(r1); • SimpleRunnable r2 = new SimpleRunnable("r2"); • Thread t2 = new Thread(r2); • t1.start(); • t2.start(); • } • } The order of start does not guarantee the order of execution.
Runnable Executor • Used to run threads that implemented Runnable • Decouples task creating and task running: • Class does not have to be ran right after creation • Creating the Executor: • ExecutorService e = Executors.newFixedThreadPool(<numberOfThreads>); • numberOfThreads: maximal number of threads running at same time. • Executing the thread: • e.execute(Runnable object); • Shutting down executor: • e.shutdown() • Causes the executor not to accept any new threads, and close all threads when all submitted tasks are done.
Using Executor - Threads01e.java class SimpleRunnable implements Runnable { private int m_number; public SimpleRunnable(int i) { this.m_number = i; } /** * Main lifecycle of the task. * Prints the task ID 10 times. */ public void run() { for (int i = 0; i < 10; i++) { System.out.print(" " + m_number); } } }
import java.util.concurrent.*; public class Threads01e { public static void main(String[] a) { // Create an executor: ExecutorService e = Executors.newFixedThreadPool(3); // create 10 runnables, and execute them. for(int i=0;i<10;i++) { System.out.println("creating a new task: " + i + " "); SimpleRunnable r = new SimpleRunnable(i); e.execute(r); } e.shutdown(); } }
Extending Java Threads • Java.lang.Thread • Allows maximal threading functionality • Less common than Runnable, however much more powerful. • Requires one method to be implemented: • public void run() • Implementation: class <classname> extends Thread{ public void run(){ //thread “main” function } }
Threads can be Dangerous • Having things run "at the same time, in the same place", can be dangerous. • The two tasks can interfere with each other, and unexpected results might occur.
Example – shared counter public class Counter{ private int fCounter; public Counter(){ fCounter = 0; } public void increment(){ fCounter++; } public int getValue(){ return fCounter; } }
public class Incrementer implements Runnable { Counter fCounter; Incrementer(Counter ctr) { fCounter = ctr; } /** * Main lifecycle. * increment the counter 200 times then dies. */ public void run() { for (int i = 0; i<200; i++) { fCounter.increment(); } } }
public class Threads03{ • // Demonstrating problems with access to a shared resource. • public static void main(String[] a) { • for (int i=1;i<10;i++){ • // create our shared object • Counter ctr = new Counter(); • Thread t1 = new Thread(new Incrementer(ctr)); • Thread t2 = new Thread(new Incrementer(ctr)); • t1.start(); • t2.start(); • //wait until their job is done • while (t1.isAlive() || t2.isAlive()); //wait until all done. • //print out result of attempt i • System.out.println("Attempt " + i + ", total value: " + ctr.getValue()); • } • } • } • }
Shared Resources and Safety • Safety problems arise when multiple threads access the same resource. • A shared resource is any object that is visible to several threads: • global (static) objects • non-primitive method parameters • class members. • Basically non-primitive variables.
class Foo { public static double NUMBER = 33.3; } class ClassA { public long i; public Vector v; public ClassA() { /* ... */ } public void doSomething(long x, List lst) { long localVar = 0; Object o; o = this.v.elementAt(2); localVar += 2; this.i += 2; x += 2; lst.elementAt(2); Foo.NUMBER = 4; localVar = Foo.NUMBER ; } } class TaskA implements Runnable { //... private ClassA a; private List lst; public long r; public void run() { this.r = 2; this.a.doSomething(9, lst); } } class Main { public static void main(String[] args) { // .... ClassA o1 = new ClassA(); Thread t1 = new Thread(new TaskA(o1)); t1.start(); // .... } } Not safe - Accessing a public member variable. Not Safe - The private member variable (lst) is exposed to class A. Not safe - Accessing a public member variable. Local variable - Safe Not safe - Accessing a public member variable. Primitive- Safe Not Safe - Accessing a possible shared object (lst). Not Safe (static - never safe!) Not Safe (static - never safe!)
Some Solutions • Thread-confined A thread-confined object is owned exclusively by and confined to one thread, and can be modified only by the thread that owns it. • Shared read-only A shared read-only object can be accessed concurrently by multiple threads, but cannot be modified by any thread. Shared read-only objects are immutable.
Solution 1 - Thread Confinement • Problem is solved by not accessing the shared resources! By not having shared resources. • Called thread confinement: • threads access local resources only. • This way, no need to worry about thread safety since no thread can access any other thread’s variables.
Example //NotThreadConfined // e is not confined to this method - it is visible from the outside public Car createCar(Engine e) { List<Door> doors = new LinkedList<Door>(); doors.add(new FrontDoor()); doors.add(new FrontDoor()); doors.add(new BackDoor()); doors.add(new BackDoor()); Radio r = new AMFMRadio(); Car c = new Car(e, doors, r); return c; } //ThreadConfined public Car createCar() { Engine e = new FuelEngine(); List<Door> doors = new LinkedList<Door>(); doors.add(new FrontDoor()); doors.add(new FrontDoor()); doors.add(new BackDoor()); doors.add(new BackDoor()); Radio r = new AMFMRadio(); Car c = new Car(e, doors, r); return c; }
Solution 2 - Immutability • An immutable object cannot be changed after construction. • Solves thread safety problem by not allowing any variable modifications at all.
Immutable Class - conditions • All of its fields are final • The class is declared final (cannot be subclassed) • The this reference is not allowed to escape during construction. (the object is not fully constructed!) For more info: http://www.ibm.com/developerworks/java/library/j-jtp0618/ • Any fields that contain references to mutable objects, such as arrays, collections, or mutable classes like Date: • Are private • Are never returned or otherwise exposed to callers • Are the only reference to the objects that they reference • Do not change the state of the referenced objects after construction
/** * The constructed class is immutable even-though it consists of mutable objects. * The class is immutable due to its design, not just by using the final keyword. * class ThreeStooges is declared to be final, which means that it cannot have subclasses. */ public final class ThreeStooges { private final Set<String> stooges = new HashSet<String>(); public ThreeStooges() { stooges.add("Moe"); stooges.add("Larry"); stooges.add("Curly"); } public boolean isStooge(String name) { return stooges.contains(name); } } it won't change after construction, meaning it won't be assigned with another reference, but still the object stooges is mutable: its internal values may change