Download Java Threading: Creating, Managing, and Synchronizing Threads - Prof. Mark Weiss and more Study notes Computer Science in PDF only on Docsity!
1
Threads and Synchronization
Mark Allen Weiss
Copyright 2000
2
Outline of Topics
l What threads are
l The Thread class and starting some threads
l Synchronization: keeping threads from
clobbering each other
l Deadlock avoidance: keeping threads from
stalling over each other
3
Multitasking
l Multitasking means that you can have several
processes running at same time, even if only
one processor.
l Can run a browser, VM, powerpoint, print job,
etc.
l All modern operating systems support
multitasking
l On a single processor system, multitasking is
an illusion projected by operating system
4
Threads
l Inside each process can have several threads
l Each thread represents its own flow of logic
- gets separate runtime stack
l Modern operating systems support threading
too; more efficient than separate processes
l Example of threading in a browser:
- separate thread downloads each image on a page
(could be one thread per image)
- separate thread displays HTML
- separate thread allows typing or pressing of stop
button
- makes browser look more responsive
7
l VM has threads in background
l VM alive as long as a “legitimate thread” still
around (illegitimate threads are “daemons”)
l GUI programs will start separate thread to
handle events once frame is visible
main thread
garbage collector
event thread
(once container is visible)
Threads in the Virtual Machine
8
Thread Class
l Use Thread class in java.lang
l Two most important instance methods:
- start : Creates a new thread of execution in the
VM; then, invokes run in that thread of execution;
current thread also continues running
- run : explains what the thread should do
l Thread is not abstract, so there are default
implementations
- start does what is described above; should be final
method (but isn’t)
9
Creating A Do Nothing Thread
l The following code creates a Thread object,
then starts a second thread.
public static void main( String[] args ) {
Thread t = new Thread( );
t.start( ); // now two threads, both running
System.out.println( “main continues” );
}
l In code above:
- First line creates a Thread object, but main is the
only running thread
- Second line spawns a new VM thread. Two threads
are now active.
- main thread continues at same time as new thread
calls its run method (which does nothing)
10
Getting Thread to Do Something
l Option #1: extend Thread class, override run
method
class ThreadExtends extends Thread {
public void run( ) {
for( int i = 0; i < 1000; i++ )
System.out.println( "ThreadExtends " + i );
}
}
class ThreadDemo {
public static void main( String[] args ) {
Thread t1 = new ThreadExtends( );
t1.start( );
for( int i = 0; i < 1000; i++ )
System.out.println( "main " + i );
}
}
13
Anonymous Implementation
l May see the Runnable implemented as an
anonymous class in other people’s code
class ThreadDemo {
public static void main( String[] args ) {
Thread t3 = new Thread ( new Runnable( ) {
public void run( ) {
for( int i = 0; i < 1000; i++ )
System.out.println( "ThreadAnonymous " + i );
}
}
);
t3.start( );
for( int i = 0; i < 1000; i++ )
System.out.println( "main " + i );
}
}
14
Common Mistake #
l You should NEVER call run yourself
will not create new VM thread
- will not get separate stack space
- will invoke run in the current thread
l start don’t run
15
Thread States
l Thread is not runnable until start is called
l Thread can only unblock if cause of blocking is
resolved
new
dead
runnable
blocked
start
constructor
sleep, wait, blocked on I/O
time expires, notifyAll, I/O complete
run terminates
16
Is The Thread Alive?
l Cannot differentiate between being runnable
and blocked.
l Thread that is runnable or blocked is alive
l Thread that has not started or is dead is not
alive
l Can use Thread instance method isAlive to
determine thread status
19
Current Thread
l Before you can invoke any Thread instance
method, you need a reference to the current
thread
If you extend Thread , no problem. In your run
method, this represents current Thread and can
be omitted
If you use Runnable , in your run method this
represents the Runnable object. Need to use static
method Thread.currentThread
Thread self = Thread.currentThread( );
20
Deamon Threads
l By themselves do not keep a VM alive
l Can mark a thread as a daemon thread by
calling setDaemon(true)
l Call must be before call to start ; after call an
exception is thrown
l Without call to setDaemon thread’s daemon
status is same as thread that spawned it
l Can call isDaemon to see if thread is a
daemon
21
Thread Priorities
l Can suggest to VM that when there is
contention for CPU, some threads should get
preference over others.
- Only considered when there’s CPU contention;
threads that are sleeping won’t go any faster with
higher priorities
- If your program depends on priorities, you need to
do more work; VM could ignore suggestions
- Priority of thread is same as thread that created it
- Only 10 priorities ranging from
Thread.MIN_PRIORITY to
Thread.MAX_PRIORITY , with
Thread.NORM_PRIORITY
22
Current Implementations
l Windows 98/NT and Solaris Native Threads:
schedule highest priority thread
- scheduling is fully preemptive: if a new highest
priority thread becomes runnable, it gets scheduled
rule of thumb: at any given time, highest-priority
thread is running. But this is not guaranteed by
language spec.
Java platform does not time-slice, underlying thread
platform does (Solaris Green Threads does not), so
if several highest priority threads, system generally
does simple, non-preemptive round-robin
25
join
l The call t1.join( ) causes the current
thread to block until t1 terminates
l Have to catch InterruptedException
l main can join on all threads it spawns to wait
for them all to finish
26
yield
l Threads that are CPU intensive can hog all the
cycles, especially if they are high priority
l Polite thread yields every now and then
- not too often; could be spending too much time
context switching
yield
is a static method.
l Current thread
- Gives up the processor if another thread of at least
as high priority is waiting for the CPU
- If no eligible thread, current thread retains
processor
l Must catch InterruptedException
27
sleep
l Static method.
l Current thread
- Gives up the processor for at least the time specified
- Time is in milliseconds
- No guarantee that you get processor back
l Must catch InterruptedException
28
Timeouts
l can invoke wait and join with a parameter
that limits the amount of blocking (in
milliseconds)
for wait not necessarily a great idea
l Example: thread needs to do I/O; what if
nothing is typed?
Do I/O in a separate thread
- main thread does a join , with timeout on the I/O
thread
- If no I/O, main thread will continue and can
terminate itself and I/O thread if needed
31
Two Mutators Do Serious Damage
l Last example not so bad
We temporarily see object in a bad state
- Thread 1 gets time-sliced in and object gets back in
good state
Often we view objects in bad states, and we know
that current information may be inaccurate, but will
eventually be correct
l bank accounts
l frequent flyer accounts
l credit card statements
l When two mutators interact, can irreversibly
damage object state
32
Two mutators
class TwoObjs {
private int a = 15;
private int b = 37;
public int sum( ) { return a + b; } // should always be 52
public void swap( ) { int tmp = a; a = b; b = tmp; }
}
l Starting from good state
- Thread 1 invokes swap , and immediately after
executing tmp=a is time-sliced out. In this thread
tmp= .
- Thread 2 invokes swap , swapping a and b. a is now
37, b is now 15.
Thread 1 is time-sliced back in and continues: a is
now 15,
b is now
tmp , so
b is 15. OOPS!
33
Can This Really Happen?
l Yes but,
It can be fairly rare
- Depends on speed of processors
- Depends on number of processors
Depends on thread priorities
Depends on luck of the draw
l Worst kind of bug
- TwoObjs class is not thread-safe
- Could do millions of operations and never see a
problem
- Hard to know you’ve messed up
34
How Java Solves The Problem
l Use the synchronized keyword
l Marking an instance method as synchronized
means that in order to invoke it the thread
must gain possession of the “monitor” for the
invoking object (i.e. the “monitor” for this ).
l The monitor is an abstraction
every object has one and only one
- no getMonitor method, however
37
Example #
l Assume both print and swap are synchronized
- Thread #1 does obj.swap( )
l can obtain obj ’s monitor and enter
- Thread #1 is timesliced out in the middle of swap
l Thread #1 holds on to obj
’s monitor
- Thread #2 does obj.print()
l Thread #2 needs obj ’s monitor. Can’t get it, so thread is
blocked
Thread #1 is timesliced in; finishes swap
l Thread #1 releases obj ’s monitor
- Thread #3 does obj.print()
l Thread #3 gets the monitor and proceeds
38
Example #
l Assume only swap is synchronized
- Thread #1 does obj.swap( )
l can obtain obj ’s monitor and enter
- Thread #1 is timesliced out in the middle of swap
l Thread #1 holds on to obj
’s monitor
- Thread #2 does obj.print()
l Thread #2 does not need obj ’s monitor, so it proceeds
Thread #1 is timesliced in; finishes swap
l Thread #1 releases obj ’s monitor
39
Example #
l Assume swap is synchronized, and obj1 and
obj2 are different objects
- Thread #1 does obj1.swap( )
l can obtain obj1 ’s monitor and enter
- Thread #1 is timesliced out in the middle of swap
l Thread #1 holds on to obj
’s monitor
- Thread #2 does obj2.print()
l can obtain obj2 ’s monitor and enter, so it proceeds
l when it finishes it releases obj
’s monitor
- Thread #1 is timesliced in; finishes swap
l Thread #1 releases obj1 ’s monitor
40
Static Methods
l Synchronized static methods require the
obtaining of a monitor also
can’t be the objects monitor because there is not
- the monitor it needs to obtain the monitor for the
Class object.
l May be important for fancy stuff
l Just remember that instance methods and
static methods use different monitors