Download Java Threads (a review, and some new things)

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Class (computer programming) wikipedia , lookup

Object-oriented programming wikipedia , lookup

Falcon (programming language) wikipedia , lookup

Java (programming language) wikipedia , lookup

Name mangling wikipedia , lookup

Join-pattern wikipedia , lookup

C Sharp syntax wikipedia , lookup

Parallel computing wikipedia , lookup

C Sharp (programming language) wikipedia , lookup

Java performance wikipedia , lookup

Scheduling (computing) wikipedia , lookup

Monitor (synchronization) wikipedia , lookup

Thread (computing) wikipedia , lookup

Transcript
Java Threads
(a review, and some
new things)
ICS432 - Spring 2017
Concurrent and High-Performance
Programming
Henri Casanova ([email protected])
Threads in Programming Languages
!
Almost all programming languages provide
constructs/abstractions for writing concurrent
programs
"
!
Java does it like it does everything else, by
providing a class (Thread) and an interface
(Runnable)
"
!
even old ones (Modula, Ada, etc.)
You create a thread/runnable object, and then
start a thread
Java provides several higher level
abstractions, which we’ll see later in the
semester
"
It’s important to first master the “low level” stuff
Extending the Thread class
!
One option: extend the thread class and
override its “run()” method
public class MyThread extends Thread
{
public void run() {
. . .
}
. . .
}
myThread t = new MyThread();
!
But the preferred method is to use the
Runnable interface…
The Runnable Interface
!
Using the Runnable interface is preferred
because then you can still extend another class
" Java doesn’t have multiple inheritance, so
typically
" So if you can use an implements instead of
an extends, you should
!
!
So that you keep that option open for another
purpose
Let’s see an example…
Runnable Example
public class RunnableExample {
}
class MyTask implements Runnable {
public void run() {
for (int i=0; i<500; i++)
System.out.print("#");
}
}
public RunnableExample() {
Thread t = new Thread(new MyTask());
t.start();
for (int i=0; i<500; i++)
System.out.print(".");
}
public static void main(String args[]) {
RunnableExample p = new RunnableExample();
}
Spawning a thread
!
!
To launch, or spawn, a thread, you just call
the thread’s start() method
WARNING: Don’t call the run() method
directly to launch a thread
"
If you call the run() method directly, then you
just call some method of some object, and the
method executes
!
"
Fine, but probably not what you want
The start() method, which you should not
override, does all the thread launching
!
!
It launches a thread that starts its execution by
calling the run() method
It gets the OS to do all its things to start a new thread
What happens
!
The previous program runs as a Java process
"
!
!
that is, a thread running inside the JVM
When the start() method is called, the main thread
creates a new thread
We now have two threads
The “main”, “original” thread
" The newly created thread
"
!
Both threads are running
The main thread prints ‘.’ 500 times to the screen
" The new thread prints ‘#’ 500 times to the screen
and exits
"
!
When both threads are finished, then the process
terminates
What happens
Host
JVM process
Your
program’s
main thread
Newly
created
thread
On this laptop
On a Linux Box
Non-deterministic Execution!
!
!
Running our simple program shows one
difficulty with multithreaded programming,
and especially for debugging: it is difficult
to tell what the execution will look like
The OS schedules when a thread runs
"
!
!
In ICS332 you learned all the “smarts”
implemented in the kernel to schedule threads
efficiently
But Java provides ways to influence thread
scheduling at the JVM level
Let’s see what we can do...
The Thread class
package java.lang;
public class Thread implements Runnable {
public void start();
public void run();
public boolean isAlive();
public Thread.State getState();
public static void sleep(long millis);
public static void sleep(long millis,
long nanos);
// A bunch of other things we’ll discuss later
...
}
The isAlive() Method
!
!
When you spawn a thread you may not really know when
or how it is going to terminate
It may be useful to know
"
!
!
To see if the thread’s work is done for instance
The isAlive() method returns true is the thread is running,
false otherwise
Could be useful to restart a thread
if (!t.isAlive()) {
t.start();
}
The getState() method
!
The possible thread states are
"
"
NEW: A thread that hasn’t been started yet
RUNNABLE: The thread can be run, and may be running as
we speak
!
"
BLOCKED: The thread is blocked on a monitor
!
"
See future lecture
TIMED_WAITING: The thread is waiting for another thread to
do something, but will give up after a specified time out
!
"
See future lecture
WAITING: The thread is waiting for another thread to do
something
!
"
It might not because another runnable thread could be running
See future lecture
TERMINATED: The thread’s run method has returned
! isAlive() would return false
Thread Lifecycle: 4 states
RUNNABLE
NEW
running
not
running
TERMINATED
BLOCKED/
WAITING/
TIMED_WAITING
Thread Lifecycle: 4 states
RUNNABLE
NEW
start()
running
not
running
TERMINATED
BLOCKED/
WAITING/
TIMED_WAITING
Thread Lifecycle: 4 states
sleep()
block on I/O
wait()
RUNNABLE
NEW
start()
running
not
running
TERMINATED
BLOCKED/
WAITING/
TIMED_WAITING
Thread Lifecycle: 4 states
sleep()
block on I/O
wait()
RUNNABLE
NEW
start()
running
not
running
BLOCKED/
WAITING/
TIMED_WAITING
time elapsed
I/O done
notify()
TERMINATED
Thread Lifecycle: 4 states
sleep()
block on I/O
wait()
RUNNABLE
NEW
start()
running
not
running
run() method
returns
TERMINATED
BLOCKED/
WAITING/
TIMED_WAITING
time elapsed
I/O done
notify()
Java Threads / Kernel Threads
!
Each Java thread is mapped to a kernel thread
scheduler
thread
application
threads
O/S
JVM
Java Threads / Kernel Threads
!
This gets a bit complicated
The JVM has a thread scheduler for application threads,
which are mapped to kernel threads
" The O/S also has a thread scheduler for kernel threads
"
!
!
The JVM is itself multithreaded!
We have threads everywhere
Application threads in the JVM
" Kernel threads that run application threads
" Threads in the JVM that do some work for the JVM
"
!
!
Let’s look at a running JVM that runs a program that
does nothing and count threads....
Let’s now run a program that runs a program that
creates a thread and does nothing and count threads...
The JVM is Multithreaded
!
The previous experiment shows that the JVM is
highly multithreaded
"
!
22 threads besides your own program, with my version of
Java (jdk 1.8.0_65, Mac OSX)
What are these 22 threads doing???
"
They are called “daemon threads”
!
!
Get terminated whenever non-daemon threads are all finished
Can actually be created by a Java program
One of them has to be the “JVM main thread” (my
program)
" The Garbage collector is a daemon thread
" There is an important thread called “The Event Dispatch
Thread” that we’ll talk about
" And many others...
"
So what?
!
!
!
At this point, it seems that we throw a bunch of threads in,
and we don’t really know what happens
To some extent it’s true, but we have ways to have some
control
In particular, what happens in the RUNNABLE state?
RUNNABLE
running
!
not
running
Can we control how RUNNABLE threads become running or
not running?
! This is typically controlled by the OS via scheduling
The yield() method: example
!
With the yield()
method, a thread
will pause and give
other RUNNABLE
threads the
opportunity to
execute for a while
public class MyThread extends Thread {
public void run() {
for (int i=0; i<5000; i++) {
System.out.print(“#”);
Thread.yield();
}
}
}
public class MyProgram {
public MyProgram() {
MyThread t = new MyThread();
t.start();
for (int i=0; i<5000; i++) {
System.out.print(“.”);
Thread.yield();
}
}
public static void main(String args[]) {
MyProgram p = new MyProgram();
}
}
Does Yield work?
!
Let’s try the previous code and the same code
without the calls to yield, trying to see if we have
more flip-flopping with the yield calls...
Does Yield work?
!
Let’s try the ‘#’ and ‘.’ program with and without the
calls to yield, trying to see if we have more flipflopping with the yield calls...
!
Let’s do the same but adding busy work to the
threads...
Does Yield work?
!
Let’s try the ‘#’ and ‘.’ program with and without the
calls to yield, trying to see if we have more flipflopping with the yield calls...
!
Let’s do the same but adding busy work to the
threads...
!
Conclusion: Thread.yield() does influence execution,
but we can’t rely on it for correctness
!
Many Java developers try to refrain from using yield()
Thread Priorities
!
The Thread class has a setPriority() and a
getPriority() method
"
!
A new Thread inherits the priority of the thread
that created it
Thread priorities are integers ranging
between Thread.MIN_PRIORITY and
Thread.MAX_PRIORITY
"
The higher the integer, the higher the priority
Thread Priorities and Scheduling
!
Whenever there is a choice between multiple runnable
threads, the JVM should pick the higher priority one
"
!
The JVM is preemptive
"
!
High priority threads can decide to call yield() to prevent
starvation of low-priority threads
If a new higher priority thread is started, it gets to run now
Modern JVMs use time slicing
Threads of the highest priorities get chosen in a round-robin
fashion
" The use of yield() isn’t required but, as we saw, it can increase the
frequency of switching between threads
"
!
In spite of all this:
The JVM can only influence the way in which threads are
scheduled
! And some JVM implementations ignore priorities!
" Ultimately, the decision is left to the OS
"
So what?
!
It is important to know the basics of thread
scheduling to understand the behavior of
concurrent programs
!
One should NEVER rely on scheduling
aspects to ensure correctness of the program
Since scheduling depends on the JVM and on the
OS, correctness due to scheduling is not portable
or deterministic
" The behavior on one system may be wildly
different on another, so you can never be sure
"
The join() method
!
!
!
The join() method causes a thread to wait
for another thread’s termination
This is useful for “dispatching” work to a
worker thread and waiting for it to be done
Let’s see it used on an example
A join() example
public class JoinExample {
public JoinExample() {
Thread t1 = new Thread1();
t1.start();
System.out.println("Parent thread: waiting for child to finish");
try { t1.join(); } catch (InterruptedException e) {}
System.out.println("Parent thread: child has finished");
}
public static void main(String args[]) {
JoinExample j = new JoinExample();
}
private class Thread1 extends Thread {
public void run() {
for (int i=0; i<5; i++) {
System.out.println("Child thread: iteration "+i);
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
}
}
}
Conclusion
!
Best way to create threads in Java: implement the
Runnable interface and then create a new Thread
object
!
Thread Scheduling is complex, not fully deterministic,
and must not be counted on to guarantee program
correctness
!
We can look at Exercise #1 from our programming
assignment…
For Exercise #2, we have to know a little bit about
Swing…
!