concurrent programming with threadsmercer/presentations/oopd/19... · 2014-01-20 · ri ck mercer,...

27
RICK MERCER, RICK SNODGRASS, IVAN VASQUEZ WITH HELP FROM JOSH BLOCK CONCURRENT PROGRAMMING WITH THREADS

Upload: others

Post on 07-Jul-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

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

Example (mac’s activity monitor):

Eclipse process had 33 threads at that moment

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

}

}

WHEN ARE CHANGES KNOWN?

• One thread sees the actual value of the fields

(rather than some arbitrary value in memory)

• However, a value assigned to a field by one thread may

not be visible to other threads

• The memory model defines when and how

changes made by one thread become visible to

others