CONCURRENT PROGRAMMING WITH THREADSmercer/Presentations/OOPD/19... · 2014-01-20 · RI CK MERCER,...
Transcript of CONCURRENT PROGRAMMING WITH THREADSmercer/Presentations/OOPD/19... · 2014-01-20 · RI CK MERCER,...
R I C K M E R C E R , R I C K S N O D G R A S S , I V A N V A S Q U E ZW I T H H E L P F R O M J O S H B L O C K
CONCURRENT PROGRAMMING WITH THREADS
OUTLINE
• Basic concepts
• Processes
• Threads
• Java: Thread class
• Single-threaded vs. Multi-Threads
• Concurrent Programming
• Thread Safety
CONCURRENT PROGRAMMING
• Computers with no operator system (OS) can run one
program at a time
• Only had sequential processing: executed one statement at
a time, in order until done: very intuitive (Rick did this, batch
processing) with Hollerith cards)
• An OS allows many programs to run at once
• Theses are known as Processes
• Allow better resource utilization, fairness, and convenience
• Threads running in a process share memory but have their
own program counter, stack, and local variables
• Allow better resource utilization, fairness, convenience
• Allow one process to execute on multiple processors
WHY THREADS IN A PROCESS?
• Threads provide
• responsive GUIs with a separate dedicated
thread
• fast server application throughput
• the ability to play an audio file in a separate
Thread without freezing the GUI
• Allow garbage collection (runs in its own thread)
• Allows processes to run on different processors
• Allow server apps to handle multiple clients when
each connection is allocated its own thread (a
multi-client chat servers, our next project)
PROCESSES
• Each Process has
• Program counter, Registers, Page map (address
space), Open files
• CPU context switches between processes
• Save registers of prior process
• Loads registers of current process
• loads new page map
• Processes are considered heavyweight
• lots of state
• context switch takes time
2 things at ≈ the same time
• A word processor should be able to accept input
from the user and at the same time, auto-save the
document
• Word processers have at least these two threads
1. One to handle user-input
2. Another to perform background tasks (like auto-saving)time
Thread 1 – user input
-User types some stuff
-User selects some text
-User cuts
-User pastes
-User types more stuff
Thread 2 – background task
- auto save timer limit reached
- initiate auto-save
- saving ...
- auto-save complete
- waiting
2 things at ≈ the same time
• An integrated development environment should be
abler to compile code as you type
Thread 1 – user input
-User types some stuff
-User selects some text
-User cuts
-User pastes
-User types more stuff
Thread 2 – background task
- Compile your code
- Marks errors
- waiting
THREADS
• The term thread is short for thread of control
• A process can contain multiple threads
• Threads can share the same data, while
processes each have their own set of data
• Threads are light-weight
• Java programs are executed in a thread
• the "main" thread
SINGLE THREADED
• Our Java programs have been single-threaded• Only one thread running
public class SingleThreadedExample_A {
public static void main(String[] args) {
String currentThread = Thread.currentThread().getName();
for (int i = 1; i <= 6; i++) {
try {
Thread.sleep(500); // 500 milliseconds == 0.5 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currentThread + ": " + i);
}
}
}
main: 1
main: 2
main: 3
main: 4
main: 5
main: 6
ONE WAY TO START THREADS
1. Create a class that extends java.lang.Thread
2. Override Thread’s run method
3. Create an instance of your new class
4. Send a start message to that new instance
public class SecondThread_B extends Thread {
private static int counter = 0;
public static void main(String[] args) {
Thread thread1 = new SecondThread_B();
Thread thread2 = new SecondThread_B();
Thread thread3 = new SecondThread_B();
thread1.start(); counter++;
thread2.start(); counter++;
thread3.start(); counter++;
System.out.println(Thread.currentThread().getName());
}
@Override
public void run() {
System.out.println(getName() + " counter=" + counter);
}
}
Output?
That depends
Run this code
OR IMPLEMENT RUNNABLE AND PASS REFERNCE TO A NEW THREAD
public class RunThreads_D implements Runnable {
// Run this application several times to see that the
// two threads are given processor time differently
public static void main(String[] args) {
RunThreads_D runner = new RunThreads_D();
Thread alpha = new Thread(runner); // calls overriden run
Thread beta = new Thread(runner);
alpha.setName("A");
beta.setName("B");
alpha.start();
beta.start();
}
@Override
public void run() {
// Print the name of the current Thread 500 times
for (int i = 1; i <= 500; i++) {
System.out.print(Thread.currentThread().getName() + " ");
if(i % 51 == 0)
System.out.println();
}
Output?
That depends
Run this code
START A NEW THREAD TO PLAY A SONG
1. First create a class that extends java.lang.Threadpublic class AudioFilePlayer extends Thread {
2. Override Thread’s run method (here it calls play) @Override
public void run() { // Thread’s start calls this
play();
}
public void play() {
AudioFormat decodedFormat = null;
try {
// Play audio file bits in a loop
3. Create an instance of your new classAudioFilePlayer player = new AudioFilePlayer(audioFileName);
4. Send a start message to that new instanceplayer.start();
CLIENT CODE IN SONGPLAYER
public static void playFile(EndOfSongListner wiater,
String audioFileName) {
AudioFilePlayer player = new AudioFilePlayer(audioFileName);
// Because AudioFilePlayer extends Thread
// Java will start a new Thread for you and then call
// the run() method in the subclass
player.start();
MULTI-THREADED OR NOT?
• If more than one thread is running concurrently then a
program is considered multi-threaded
• Instead of calling Thread’s start method before it calls
AudioFilePlayer run() method (bypass Thread’s start())
and just call our run() method directly from client
// Call Thread’s start() that calls our run()
// player.start(); Or do not call superclass constructor
// for a new Thread. Change SongPlayer.java in Jukebox
player.run(); // see playFile(EndOfSongListener, String)
• The GUI freezes!
• Wait until the run() method finishes (our run() method calls a
play() method that loops to read the audio file and play it.
CONCURRENCY
• Concurrency is a property of systems in which
several threads are executing at the same time,
and potentially interacting with each other
• The biggest challenge in dealing with concurrent
systems is in avoiding conflicts between threads
• When an application wants to call the same method from
two different threads
• The one method may not have finished before the switch
RACE CONDITION
• A race condition is a type of flaw in an electronic or
software system where the output is dependent on
the sequence or timing of other uncontrollable
events. The term originates with the idea of two
signals racing each other to influence the output
first, wikipedia
THREAD SAFETY
• Most Operating Systems treat threads, not processes, as the basic scheduling unit
• Threads execute simultaneously and asynchronously (separate from the main program flow) with respect to one another
• Threads share the memory address space of their owning process• all threads within a process have access to the same variables
and allocate objects from the same heap
• Without explicit synchronization to coordinate access to shared data, a thread may modify variables that another thread is in the middle of using, with unpredictable results
NON-COMPUTER EXAMPLE
• Let’s meet at the coffee shop on University at 8am• Whoops, on my way I realize there are two
• at 8:10 I wonder if you went to the other coffee shop
• You aren’t at the other one at 8:12
• What happened?
1. You didn’t show up
2. You went to see if I was at the coffee shop I just left
• How many time do we go back and forth? That depends…
• This is a real-life example of a race condition as things depend on the relative timing of events• We may meet, we may not, luck in timing is involved
A POTENTIAL RACE CONDITION
• The Singleton Design Pattern ensure 1 instance
• It uses lazy initialization: a.k.a: check then act
• When do 2 threads call getInstance() below?
• it depends…
• Maybe a 2nd thread gets control before the assignment
// NOTE: This is not thread safe!
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
NEED MUTUAL EXCLUSION
• See linked list example on Wikipedia
http://en.wikipedia.org/wiki/Mutual_exclusion
THAT DEPENDS
• One thread could update and access a different object than the other thread, then there are two instances
• Or the 2nd thread could gain access to that object while in a corrupt state (while it is being built)
• Like all race conditions, this lack of thread safety does not always result in an error
• To avoid race conditions, there must be a way to prevent other threads from using a variable while we’re in the middle of modifying it
• This ensures other threads can observe and/or modify the state only before it begins or after it’s done, but not in the middle.
ONE SOLUTION
• Mark getInstance() or LinkedList
remove as synchronized
// This is thread safe
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
SYNCHRONIZED
• synchronized ensures that only a single
thread can execute a method at one time
• synchronized methods provide
1. mutual exclusion: preventing other threads
from seeing an object while it is being
modified
• the object is in an inconsistent state
2. thread A knows about another thread B’s
changes
• Other threads are blocked out of the method until
the thread finishes
• These threads are queued up for access, which they get when the synchronized method has
finished
NOT ATOMIC
• Atomic: operation completes while locked
• Works in a single thread. Multithreaded? Maybe• ++ is actually three operations
• getCount() may or may not return correct count
• it depends on the timing
public class UnsafeCounting {
private long count = 0;
public long getCount() {
return count;
}
public void service() {
// do stuff that take some millseconds
++count;
}
}
TO BE ATOMIC OR NOT TO BE
import java.util.concurrent.atomic.AtomicLong;
public class SafeCounting {
// AtomicLong is a Thread Safe class.
private final AtomicLong count = new AtomicLong(0);
public long getCount() {
return count.get();
}
public void service() {
// do stuff but block a 2nd thread until done
count.incrementAndGet();
// Atomically incremented by one the current value
}
}