Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
CS2200 Software Development
Lecture: Multi-threading II
A. O’Riordan, 2009
1
Thread Priorities
• Java Threads have a priority – can use getPriority() method in
Thread class
• Priority is thread ranking - Some threads can either run for a longer
time-slice or run more often (depending on the operating system)
• Peers (or equals) get the same time/number of runs
• Priority is set from constants MIN_PRIORITY (currently 1) to
MAX_PRIORITY (currently 10) using the setPriority(int) method
• NORM_PRIORITY is the midrange value (currently 5).
2
Thread Priority Issues
• Higher priority threads can interrupt (pre-empt) lower priority ones
• To lower the priority of a thread by 1
t1.setPriority(t1.getPriority() -1);
• Each new thread has the same priority as that of the thread that
created it
• Low priority threads are in danger of starvation
– when one thread cannot access the CPU because one or more
other threads are monopolizing it
– yield() method relinquishes control which may enable others to
be run
3
ThreadGroup
• Every Java thread is a member of a thread group, by default the
same group as that of the thread issuing the constructor for it
– Class ThreadGroup (package java.lang)
– Add thread to group, grp, using a constructor
Thread(grp, new T(), "t1");
• Throws SecurityException if the current thread cannot create a
thread in the specified thread group
• Purpose of thread groups is to enforce security, e.g. it is not legal to
stop a thread that is not in your group
• Members of a thread group can invoke operations that affect all
members
4
Example Part I
public class ThreadGroupTest {
public static void main(String[] args){
ThreadGroup grp = new ThreadGroup(“Groupies");
Thread t1 = new Thread(grp, new Task(), "t1");
Thread t2 = new Thread(grp, new Task(), "t2");
t1.start();
t2.start();
System.out.println("ThreadGroup name:” + grp.getName());
System.out.println("There are currently " +
grp.activeCount() + " threads running");
System.out.println("The maximum priority of a Thread that
can be contained within " + grp.getName() + " is " +
grp.getMaxPriority());
}
}
5
Example Part II
class Task implements Runnable{
public void run(){
for (int i = 1; i < 5; i++) {
System.out.println("Thread " +
Thread.currentThread().getName() +
" has a priority of " +
Thread.currentThread().getPriority());
}
}
}
6
Executors (Java 5)
•
To abstract thread management from the rest of your application, pass the
application's tasks to an executor
•
Executors define a high-level API for launching and managing threads.
Executor implementations provided by java.util.concurrent provide thread
pool management suitable for large-scale applications
– ExecutorService interface that supports launching new tasks
– If r is a Runnable object, and e is an ExecutorService object you can
replace Thread t = new Thread(r); t.start() with
e.execute(r)
•
However, the definition of execute is less specific. The first option creates a
new thread and launches it immediately. Depending on the implementation,
execute may do the same thing, but is more likely to use an existing worker
thread to run r, or to place r in a queue to wait for a worker thread to
become available
7
Thread Pools
• A Thread pool consist of worker threads that exists separately from
the Runnable they execute
• A fixed thread pool always has a specified number of threads
running; if a thread is somehow terminated while it is still in use, it is
automatically replaced with a new thread
• Tasks are submitted to the pool via an internal queue, which holds
extra tasks whenever there are more active tasks than threads
• Executors method newFixedThreadPool() returns an
ExecutorService that creates 2 threads (method
newCachedThreadPool returns an ExecutorService that creates
threads as they are needed)
8
Executors Example
Assuming there’s a class Task that implements Runnable:
Task task1 = new Task("task1");
Task task2 = new Task("task2")
Task task3 = new Task("task3");
System.out.println("Starting threads");
ExecutorService threadExecutor = Executors.newFixedThreadPool(2);
threadExecutor.execute(task1);
threadExecutor.execute(task2);
threadExecutor.execute(task3);
threadExecutor.shutdown(); // shutdown worker threads
9
What’s happing
• The code in method main executes in the main thread
• Creates three Task objects (no extra threads are this stage)
• Create an executor that uses a fixed thread pool by invoking
newFixedThreadPool() factory method in Executors (returns a
ExecutorService object)
• execute() creates a new Thread inside the ExecutorService and
returns immediately from each invocation
• ExecutorService method shutdown() will end each Thread in
threadExecutor as soon as each finishes executing its Runnable
and there are none queuing
• The program will not terminate until its last thread completes
execution
10
Daemon threads
• A Java program exits when all of its threads have completed
• but this is not the full story. What about the hidden system threads,
such as the garbage collection thread and others created by the
JVM? We have no way of stopping these.
• These system threads are called daemon threads. A Java program
actually exits when all its non-daemon threads have completed
• Programmer can create daemon threads as well (not covered).
11
Process v Thread
• Process - active program – maintains its own set of resources;
Thread – sometimes called lightweight process – uses resources of
enclosing process
• Process can be considered as data (address space, files, etc) plus
one or more threads
• All threads live in the same memory space
• Threads can easily exchange data among themselves simply by
accessing shared variables (static or instance fields), but threads
must also ensure that they access shared variables in a controlled
manner
12
Technical Issues
• Deciding what should be a thread – not all objects should have their
own threads
• Liveness – a thread can be starved of CPU cycles or threads can be
deadlocked (waiting for each other in order to continue)
• Synchronization – need exclusion mechanisms to maintain threads
in a consistent state
• Non-determinism – different executions of a program can result in
different interleaving
• Thread construction overhead – performance hit of creating and
setting threads running
13
Execution context
Execution context managed by JVM
• Execution context – a way to create/delete execution context, save
and maintain state, dispatch to another thread’s execution context
• Scheduling – determine which thread to switch to and when (e.g.
run-until-blocked, round robin time-slicing)
• Synchronization – coordinate the use of shared resources, e.g.
mutexs (mutual exclusions) for shared resources; buffering for
producers and consumers
Op Sys (e.g. Linux) has it’s own execution context underneath
14
Producer/Consumer: The Box class
public class Box {
private int total;
public Box() { total = 0; }
public void put() {
int bigger = total + 1;
System.out.println("Putting something in"
+ "; new total is " + bigger);
total = bigger;
}
public void get() {
int smaller = total - 1;
System.out.println("Taking something out"
+ "; new total is " + smaller);
total = smaller;
}
}
15
Thread accessing another object
public class Producer extends Thread
{
public Box box;
public Producer(Box b) { box = b; }
public void run() {
try {
for (int i = 0; i < 50; i++) {
box.put();
sleep(100);
}
}
catch (InterruptedException e) { }
}
}
... And assume a
similar thread
for consuming
the items and a
main program
starting both
Threads…
16
Race Condition
• But the final total is not necessarily 0!
– the two threads are sharing resource, and because of thread
scheduling, there is no guarantee that the other thread does not
jump in and change it in the middle of an update
• race condition - the threads are racing to complete their tasks and
the final result depends on which one wins the race
– a thread must "lock" the data or objects it is going to change
– if an object is locked, no other object can modify its state
– Java allows us to do this by specifying that a method is
synchronized
– if the thread running it sleeps, the data remains locked
– Java handles all the locking and unlocking for us
17
Synchronizing
•
Add keyword synchronized to code:
public synchronized void get() {…}
public synchronized void put() {…}
•
this work!
Aso try to ensure co-ordinated behaviour by only put an item when box is
empty and only get an item when there is item in box
public synchronized void put(Thread th) {
while (total > 0 )
try { th.sleep(10);
} catch (InterruptedException ie) { }
// rest of code
}
... doesn't work again!
18
Deadlock
• the put() method is synchronized so once it starts, the box object is
locked, and no other thread can get access
• so if put() is invoked while total == 1, it locks the object, puts the
thread to sleep, wakes up 10 millisecs later, sees that total is 1,
goes back to sleep, and repeats for ever
• We have Deadlock!
19
Avoiding deadlock
– instead of putting the thread to sleep, we can tell the method to
wait until an appropriate time
– each time the consumer or producer changes the total, it should
notify all other threads that the value has changed
– the threads then reactivate, and check the condition
public synchronized void put() {
while (total > 0 )
try {
wait();
}
catch (InterruptedException ie) { }
int newTotal = total + 1;
notifyAll();
...
}
wait() and
notifyAll()
are methods of
the Object class
20
Resources
• Java Threads/Concurrency Tutorials
– http://java.sun.com/docs/books/tutorial/essential/concurrency/
– http://www.freejavaguide.com/java-threads-tutorial.pdf
– http://java.sun.com/j2se/1.5.0/docs/guide/concurrency/overview.html
• Dedicated Books on Java Concurrency
– Java Concurrency in Practice, Brian Goetz et al., Addison-Wesley
Professional, , 2006
– Concurrent Programming in Java, Second Edition, Doug Lea, AddisonWesley, 1999 (Java 2)
– Java Threads, Third Edition, Scott Oaks and Henry Wong, O'Reilly,
2004
21