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 Copyright © 2002, DeLorme 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 Thread instance. – 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; class TaskA implements Runnable { //... private ClassA a; private List lst; public long r; public void run() { this.r = 2; Not safe - Accessing a public member variable. public ClassA() { /* ... */ } this.a.doSomething(9, lst); Not Safe - The private member public void doSomething(long x, List lst) { } variable (lst) is exposed to class A. long localVar = 0; } Object o; class Main { Not safe - Accessing a public o = this.v.elementAt(2); member variable. public static void main(String[] args) { localVar += 2; Local variable - Safe // .... this.i += 2; Not safe - Accessing a public member variable. ClassA o1 = new ClassA(); Primitive- Safe x += 2; Thread t1 = new Thread(new TaskA(o1)); lst.elementAt(2); Not Safe - Accessing a possible shared object (lst). t1.start(); Foo.NUMBER = 4; // .... Not Safe (static - never safe!) localVar = Foo.NUMBER ; 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 //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; } //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; } 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