Threads CS 3250 Some of these slides contain material by Professor Chuck Allison.
-
Upload
david-lambert -
Category
Documents
-
view
213 -
download
0
Transcript of Threads CS 3250 Some of these slides contain material by Professor Chuck Allison.
What is a thread?
an independent unit of execution within a process
a path of execution through a program
a "lightweight process"
Sharing (or not)
Threads share the same address space and share the heap
+ Easy to communicate with other threads
- Possibility of inconsistent states
Each thread has its own execution stack
Multi-threaded vs. Single-threaded
Advantages of using more than one thread:
Single-threaded processes can't easily handle concurrent activities e.g., waiting for user I/O, network I/O, and
doing calculations at the same time Better performance if more than one
processor No guarantees Can sometimes get better performance
even if there's only one CPU. How?
Multi-threaded vs. Single-threaded
Disadvantages of using more than one thread: Race conditions and deadlock One thread can accidentally modify
another's resources. Have to deal with synchronization. Concurrency can lead to worse performance
rather than better.
Pitfalls Watch out for libraries that aren’t
thread-safe Don’t make any assumptions about
when threads will execute. Don’t use reasoning like “that will
hardly ever happen”. Testing is necessary but not
sufficient. Test on a variety of systems.
Pitfalls
Only use threads when appropriate.
“Fortunately, correct programs are frequently the simplest and have the most elegant design. Complexity should be avoided wherever possible.”
Windows System Programming, p. 223
// Illustrates Independent Threadsclass MyThread extends Thread{ private int count; public MyThread(String name, int count) { super(name); // Optional thread name this.count = count; } public void run() { for (int i = 0; i < count; ++i) System.out.println(getName()); }}
A First Example
Example by Professor Chuck Allison
public class Independent{ public static void main(String[] args) { Thread t1 = new MyThread("DessertTopping", 8); Thread t2 = new MyThread("FloorWax", 4); t1.start(); t2.start(); }}
Main program launches 2 threads
Define run(), call start()
DessertToppingDessertToppingDessertToppingFloorWaxDessertToppingFloorWaxDessertToppingFloorWaxDessertToppingFloorWaxDessertToppingDessertTopping
Output(Dependent on platform and environment -
YMMV)
The Runnable Interface
Alternative to extending java.lang.Thread
Declares a run( ) method 2 virtues:
Separates task from thread objects Leaves you free to extend another
class Java only supports single inheritance
Thread has a constructor that takes a Runnable object
class MyTask implements Runnable { private int count; private String name;
public MyThread(String name, int count){this.count = count;this.name = name;
}
public void run(){ for (int i = 0; i < count; ++i) System.out.println(name); }}
The Runnable interface
public class IndependentR { public static void main(String[] args) { Thread t1 = new Thread(
new MyTask("DessertTopping", 8)); Thread t2 = new Thread(
new MyTask("FloorWax", 4)); t1.start(); t2.start(); }}
Create threads fromRunnable objects
Blocking I/O Note that the calls to println( ) run
uninterrupted I/O is a blocking operation
The thread waits until it completes Other threads may run, but the I/O will be
undisturbed Reason: I/O is coarse-grained native code
JDK 1.4 java.nio provides non-blocking I/O Buffers, channels, selectors, for more fine-
grained control One thread can manage multiple
connections
Interleaved I/Oclass MyThread extends Thread{ // <snip> public void run() { for (int i = 0; i < count; ++i) { display(); // Replaces println() } } void display() { String s = getName(); for (int i = 0; i < s.length(); ++i) System.out.print(s.charAt(i)); System.out.println(); }} Example by Professor Chuck Allison
Output (interleaved – oops!)
DessertToppingDFloorWaxFloorWaxFloorWaxFloorWessertToppingDesaxsertToppingDessertToppingDessertToppingDessertToppingDessertToppingDessertTopping
Race Conditionresult of executing program(s) depends on who runs precisely when
b = getBalance(“1234”);b += 500;setBalance(“1234”, b);
b = getBalance(“1234”);
b -= 100;setBalance(“1234”, b);
Thread 1 Thread 2
balance starts at 1000
What should the ending balance be? What will it be?Will getting rid of the local variable b solve the problem?How can we solve this problem?
Synchronization
Need to prevent race conditions Critical region
Part of a program that accesses shared memory (or another shared resource)
To prevent race conditions, only allow one thread at a time to enter critical region
Locks and Monitors Every object has a hidden lock object
Used to protect code blocks Monitor concept
Only allows one thread in at a time Thread acquires a lock via some object Other related threads wait until lock is
released Applies to all guarded methods for that
object only Achieved with the synchronized
keyword Protects code (not data directly) Make data private!
synchronized void f(){ <protected code>}
How synchronized works(conceptually)
Very important. Why?
void f() {this.lock.acquire();try{ <protected code>}finally{ this.lock.release();}}
is the same as the following pseudocode…
Library Example
Check-out system Usually solved by database locks, but
humor me Book class Must only allow one thread access
to check-out check-in code Synchronized methods
// Illustrates synchronized methods
class Book{ private final String title; private final String author; private String borrower;
public Book(String title, String author) { this.title = title; this.author = author; borrower = null; }
public synchronized boolean checkOut(String borrower) { if (isAvailable()) { this.borrower = borrower; return true; } else return false; }
public synchronized boolean checkIn() { if (!isAvailable()) { borrower = null; return true; } else return false; }
public String getTitle() { return title; }
public String getAuthor() { return author; }
public synchronized boolean isAvailable() { return borrower == null; }
public synchronized String getBorrower() { return borrower; }}
Principles Always make data private Always protect access to shared
data with a monitor (i.e., using synchronized)
Synchronize as little code as possible Blocks instead of entire methods:
{… synchronized (obj) {…} … }
Synchronizing displayclass MyThread extends Thread{ private static Object lock = new Object(); // <snip>
void display() {
synchronized(lock) { String s = getName(); for (int i = 0; i < s.length(); ++i) System.out.print(s.charAt(i)); System.out.println();
} }}
DessertToppingFloorWaxDessertToppingDessertToppingFloorWaxDessertToppingDessertToppingFloorWaxDessertToppingDessertToppingFloorWaxDessertTopping
Output (not interleaved)
A simpler way of synchronizing display
synchronized static void display(String s){
for (int i = 0; i < s.length(); ++i)System.out.print(s.charAt(i));
System.out.println();}
Will use lock on class object
Threads and Exceptions
Exceptions belong to a thread Both are stack-based
When an exception occurs in a monitor, the lock is released
For uncaught exceptions, the current thread dies ThreadGroup.uncaughtException() is
called, which prints the stack trace as its default behavior