- Self contained execution environment
- Own memory space
- Interprocess execution environment
- Process have at least one
- Instantiate own
Threads on demand - Pass tasks to an
Executor(As described later)
- Two methods:
- Best practice: define
Runnableclass object - Other option: Extend
Threadand executeThread.run()
- Best practice: define
Thread.sleep()
- Suspends thread for defined time
- Not guaranteed to be precise. It's as precise as the OS may be
- Cannot assume it will not be interrupted
- Usually given with
InterruptedException - Thread should stop and do something else
- Very common for stopping threads
- Waits for a
Threadto complete - Can have timeout like
Thread.sleep()throwingInterruptedExceptionwhen timed out
SimpleThreads Example
public class SimpleThreads {
// Display a message, preceded by
// the name of the current thread
static void threadMessage(String message) {
String threadName =
Thread.currentThread().getName();
System.out.format("%s: %s%n",
threadName,
message);
}
private static class MessageLoop
implements Runnable {
public void run() {
String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
try {
for (int i = 0;
i < importantInfo.length;
i++) {
// Pause for 4 seconds
Thread.sleep(4000);
// Print a message
threadMessage(importantInfo[i]);
}
} catch (InterruptedException e) {
threadMessage("I wasn't done!");
}
}
}
public static void main(String args[])
throws InterruptedException {
// Delay, in milliseconds before
// we interrupt MessageLoop
// thread (default one hour).
long patience = 1000 * 60 * 60;
// If command line argument
// present, gives patience
// in seconds.
if (args.length > 0) {
try {
patience = Long.parseLong(args[0]) * 1000;
} catch (NumberFormatException e) {
System.err.println("Argument must be an integer.");
System.exit(1);
}
}
threadMessage("Starting MessageLoop thread");
long startTime = System.currentTimeMillis();
Thread t = new Thread(new MessageLoop());
t.start();
threadMessage("Waiting for MessageLoop thread to finish");
// loop until MessageLoop
// thread exits
while (t.isAlive()) {
threadMessage("Still waiting...");
// Wait maximum of 1 second
// for MessageLoop thread
// to finish.
t.join(1000);
if (((System.currentTimeMillis() - startTime) > patience)
&& t.isAlive()) {
threadMessage("Tired of waiting!");
t.interrupt();
// Shouldn't be long now
// -- wait indefinitely
t.join();
}
}
threadMessage("Finally!");
}
}- Locks done through internal Java API known as
monitors - Allows only one thread to hold the lock
- 2 threads accessing at once causes one to block until other gives up the
monitor - Automatic acquisition and release when using synchronize'd methods
- Static methods provide class level locks
- Allows
Objectto be specified as the intrinsic lock Example usinglock1andlock2as locks:
public class MsLunch {
private long c1 = 0;
private long c2 = 0;
private Object lock1 = new Object();
private Object lock2 = new Object();
public void inc1() {
synchronized(lock1) {
c1++;
}
}
public void inc2() {
synchronized(lock2) {
c2++;
}
}
}- Must be careful with using this method
- Make sure interleaving access to the fields is alright
- References and primitives are atomic writes
- Except
longanddouble
- Except
- Reads are atomic for all volatile variables
- Atomic access is more efficient than synchronize'd code
- It requires more care, however
- Two
Threads waiting for each other to do something Threads will never end and must be interrupted
- synchronize'd method which is slow
- One
Threadcalls method many times - Another
Threadmust now wait long periods before using method
- Two
Threads constantly responding to eachother - Not technically blocked, simply too busy to respond
- Coordinated actions between
Threads - Works by polling a condition that must be true to continue
- Uses
Object.wait()until interrupted and condition check can try again
public synchronized void guardedJoy(){
while ( ! joy ){
try {
wait();
} catch ( InterruptedException e ) {}
}
System.out.println("We have joy!");
}- Note the
InterruptedExceptionis not the end of the loop, it just works to start theThreadback up and check the conditional once more - Invoking
wait()inside synchronize'd methods is an easy way to acquire the intrinsic lock Object.notifyAll()is usually better thanObject.notify()Object.notify()does not specify whichThreadis woken up- Java Collections Framework has guarded block objects
- Very similar to implicit locks
- Support wait/notify through condition objects
- Advantages:
- Can back out of lock acquisition attempt
Lock.tryLock()backs out if not available or times outLock.lockInterruptibly()backs out if anotherThreadinterrupts prior to acquisition
- 3 Interfaces:
- Executor - Launcher for new tasks
- ExecutorService - Subinterface of
Executorwith lifecycle management features - ScheduledExecutorService - Scheduled subinterface of
ExecutorService
Executor.execute(Runnable)- The
java.util.concurrentimplementation uses worker threads and more advanced functionality such as thread pools
ExecutorService.submit(Runnable || Callable)- Returns
Futureobject - Retrieves
Callablereturn value - Manages status of
CallableandRunnabletasks - Methods for submitting
Collections ofCallabletasks - Manages shutdown of the
Executor
- Executes
RunnableorCallabletasks after a delay ScheduledExecutorService.scheduleAtFixedRate()ScheduledExecutorService.scheduleWithFixedDelay()
- Minimizes
Threadobjects to instantiate - Alloc/Dealloc of
Threadmemory space is expensive - Fixed Thread Pool:
- Specified number of
Threads - Terminated
Threads are replaced with new ones - Submitted via internal queue for when there are more tasks than available
worker
Threads - Graceful degredation
- Can't spin up more
Threads - Keeps execution within system limits, even when many tasks
- Implementation of
ExecutorService - Built for multicore/many processors
- Designed for small units of work built recursively
- Goal is to use all available hardware power
- Uses worker threads in a thread pool
- Idle worker threads steal tasks from other busy threads
- ForkJoinTask
- Usually RecursiveTask or RecursiveAction Impl
if ( work is small enough )
do it all
else
split the work
invoke this on each piece and wait for results
Written with StackEdit.