Intro to Threads and State Machines

advertisement

INTRO TO THREADS

CIS 4350

Rolf Lakaemper

Threads

Definitions first (Wikipedia):

“In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by an operating system scheduler… Multiple threads can exist within the same process and share resources such as memory”

Example

Let’s start with a simple example.

We want to write a program, that prints out a text every second.

Bad Implementation

public static void main(String[] args) { long time = System.currentTimeMillis(); int counter = 0; while (true) { long currentTime = System.currentTimeMillis(); if (currentTime - time > 1000) { time = currentTime;

System.out.println("Hello “+ counter)); counter++;

}

}

}

Better yet Limited Implementation

public static void main(String[] args) throws InterruptedException

{ long time = System.currentTimeMillis(); int counter = 0; This is a pause command. It indirectly points us to Threads, but let’s not care right now.

while (true) {

Thread.sleep(1000);

System.out.println("Hello " + counter); counter++;

}

}

Example

The limitation is, that the program

(a) pauses for 1 second

(b) requires a loop to be performed!

Let’s extend the task, so these limitations become clear:

We want the user to be able to end the program, by clicking ok in a dialog box. Unfortunately, when creating a dialog box, it waits for input (if we choose JOptionPane.showMessageDialog)).

Example

This does not work!

Wait a second

Print Time

Get input

End

It’s stuck right here!

Example

What we need is a user input that does not wait.

JAVA of course provides these, but, for this example, let’s build our own version.

Our non-waiting box will explain why Threads are needed: our example problem is trying to handle two tasks: printing the time and waiting for input.

This problem can be modeled in a more elegant way than in a single loop:

A better solution to our problem

We have one process (our program), with two sub-processes (THREADS), that run independently, yet communicate via a field (break flag)

Process

Thread 1 Thread 2

Wait a second

Print Time

Check break-flag

End

Break flag

Get User Input

Set break flag

Back to the Definition

“…a thread of execution is the smallest sequence of programmed instructions that can be managed independently by an operating system scheduler…

Our two threads! The time-print-thread, and the input-thread.

Multiple threads can exist within the same process and share resources such as memory”

Our process: one program. The shared resource: the break flag.

How to Code Threads in JAVA

When you start your usual JAVA program, it runs in a single thread, which starts the method main().

Additional Threads can be started by instantiating classes of Type “Runnable”, i.e. classes that implement the “Runnable” interface.

“Runnable” declares the method “run()”

There’s a default implementation, the “Thread” class, we can extend our own classes from.

The example revisited

Process

Thread 1 Thread 2

Break flag

Main Process

public class Main { private boolean breakFlag; class TimePrint extends Thread {

} class UserInput extends Thread {

}

// ----------------------------

Main() { breakFlag = false; new TimePrint().start(); new UserInput().start();

}

} public static void main(String[] args) throws InterruptedException { new Main();

}

Remark:

We are starting 3 threads here!

1.

“main”

2.

3.

Thread1

Thread2

“main” just dies after creating the other two.

Thread1 dies when the break-condition is true

Thread2 dies when ok was clicked.

The process terminates when all threads are dead,

NOT when main terminates!

Thread 1

class TimePrint extends Thread { public void run(){ int counter = 0; while (!breakFlag){ try {

Thread.sleep(1000);

}

} catch (InterruptedException ex) {

System.out.println("Hello "+counter); counter++;

}

}

}

Shared resource!

Thread 2

class UserInput extends Thread { public void run(){

JOptionPane.showMessageDialog(null, "Stop the

Program"); breakFlag = true;

}

}

Shared resource!

Version 2: Implementation of the Runnable interface (example: Thread 2)

class UserInput implements Runnable { public void run(){

JOptionPane.showMessageDialog(null, "Stop the Program"); breakFlag = true;

}

}

… this version needs to be started using: new Thread(new UserInput()).start();

Advanced

Threads can have multiple “states”

We might talk about that later.

…but we don’t necessarily have to.

Problems with Threads: Concurrency

We share resources!

If one thread writes to a resource while another one reads from it, we might be in trouble!

(the problem is that we only MIGHT be in trouble. One time we are, another we are not, which makes debugging ugly!)

The trouble: if the resources consist of multiple parts (e.g. an array, consisting of many members). If thread1 re-writes a part while thread2 reads another part, thread2 might have different partial versions of the resource read after completion. Even worse: if thread1 deletes the resource, while thread2 reads it, the program might crash!

If resources consist of only a single part, everything is fine.

Concurrency

time

Thread1

Starts to read

Thread2 writes

Thread1

Continues to read

Thread1

Reading result:

Array Array Array Array

“Single Part” resources are ok

time

Thread1

Starts and finishes reading

Thread2 writes

Thread1

Reading result:

Solution: make multi-part resources

“Thread safe” - locking

A resource is thread safe when its access is

“atomic”, i.e. a single virtual access cycle is needed.

This can be achieved by “locks”, which regulate access order.

Example:

Concurrency: Locking Example

Version 1: no locking. Concurrency problem

Method1

Access to

Array

Method2

Access to

Array

Trouble!!!

Array

Concurrency: Locking Example

Version 1: locking. No concurrency problem

Method1

Access to

Array

Lock

Access

Unlock

Method2

Access to

Array

Array

Locks

A lock is an atomic resource

It has two methods, which are virtual one cycle methods: lock() and unlock()

If a locked resource is attempted to be locked again, it blocks the access (makes the Thread wait) until it gets unlocked.

“Locking” a data structure is to surround the multicycle access to it with a lock.

Java Example

(example, see course website: “ThreadExamples”)

Download