Java Unit 4
Java Unit 4
1. Multithreaded Programming
2. I/O basics
3. Applets
4. Generics
Multitasking and Multithreading
Multitasking refers to a computer's ability to perform
multiple jobs concurrently
more than one program are running concurrently, e.g., UNIX
A thread is a single sequence of execution within a
program
Multithreading refers to multiple threads of control within
a single program
each program can run multiple threads of control within it, e.g.,
Web Browser
Concurrency vs. Parallelism
CPU CPU1 CPU2
Threads and Processes
CPU
main
run
GC
What are Threads Good For?
To maintain responsiveness of an application
during a long running task.
To enable cancellation of separable tasks.
Some problems are intrinsically parallel.
To monitor status of some resource (DB).
Some APIs and systems demand it: Swing.
Application Thread
When we execute an application:
The JVM creates a Thread object whose task is defined
by the main() method
It starts the thread
The thread executes the statements of the program one
by one until the method returns and the thread dies
Multiple Threads in an Application
Each thread has its private run-time stack
If two threads execute the same method, each will
have its own copy of the local variables the methods
uses
However, all threads see the same dynamic memory
(heap)
Two different threads can act on the same object and
same static fields concurrently
Creating Threads
There are two ways to create our own Thread
object
1. Subclassing the Thread class and instantiating a
new object of that class
2. Implementing the Runnable interface
In both cases the run() method should be
implemented
Extending Thread
public class ThreadExample extends Thread {
public void run () {
for (int i = 1; i <= 100; i++) {
System.out.println(“Thread: ” + i);
}
}
}
Thread Methods
void start()
Creates a new thread and makes it runnable
This method can be called only once
void run()
The new thread begins its life inside this method
void stop() (deprecated)
The thread is being terminated
Thread Methods
yield()
Causes the currently executing thread object to
temporarily pause and allow other threads to execute
Allow only threads of the same priority to run
sleep(int m)/sleep(int m,int n)
The thread sleeps for m milliseconds, plus n nanoseconds
Implementing Runnable
public class RunnableExample implements Runnable {
public void run () {
for (int i = 1; i <= 100; i++) {
System.out.println (“Runnable: ” + i);
}
}
}
A Runnable Object
The Thread object’s run() method calls the
Runnable object’s run() method
RESULT
Scheduling Threads
start()
Ready queue
Newly created
threads
Currently executed
thread
I/O operation completes
Alive
Running
new ThreadExample(); while (…) { … }
Blocked
Object.wait()
Thread.sleep()
blocking IO call
waiting on a monitor
Example
public class PrintThread1 extends Thread {
String name;
public PrintThread1(String name) {
this.name = name;
}
public void run() {
for (int i=1; i<500 ; i++) {
try {
sleep((long)(Math.random() * 100));
} catch (InterruptedException ie) { }
System.out.print(name);
}}
Example (cont)
public static void main(String args[]) {
PrintThread1 a = new PrintThread1("*");
PrintThread1 b = new PrintThread1("-");
PrintThread1 c = new PrintThread1("=");
a.start();
b.start();
c.start();
}
}
RESULT
Scheduling
Thread scheduling is the mechanism used to
determine how runnable threads are allocated CPU
time
A thread-scheduling mechanism is either
preemptive or nonpreemptive
Preemptive Scheduling
Preemptive scheduling – the thread scheduler
preempts (pauses) a running thread to allow different
threads to execute
Nonpreemptive scheduling – the scheduler never
interrupts a running thread
The nonpreemptive scheduler relies on the running
thread to yield control of the CPU so that other
threads may execute
Starvation
A nonpreemptive scheduler may cause starvation
(runnable threads, ready to be executed, wait to be
executed in the CPU a lot of time, maybe even
forever)
Sometimes, starvation is also called a livelock
Time-Sliced Scheduling
Time-sliced scheduling – the scheduler allocates a
period of time that each thread can use the CPU
when that amount of time has elapsed, the scheduler
preempts the thread and switches to a different thread
Nontime-sliced scheduler – the scheduler does not
use elapsed time to determine when to preempt a
thread
it uses other criteria such as priority or I/O status
Java Scheduling
Scheduler is preemptive and based on priority of
threads
Uses fixed-priority scheduling:
Threads are scheduled according to their priority w.r.t.
other threads in the ready queue
Java Scheduling
The highest priority runnable thread is always selected for
execution above lower priority threads
When multiple threads have equally high priorities, only one
of those threads is guaranteed to be executing
Java threads are guaranteed to be preemptive-but not time
sliced
Q: Why can’t we guarantee time-sliced scheduling?
PrintWriter writer =
new PrintWriter(
new OutputStreamWriter(
connection.getOutputStream()));
// A client of an HelloServer
class HelloClient {
deposit()
Bank Account
Static Synchronized Methods
Marking a static method as synchronized,
associates a monitor with the class itself
The execution of synchronized static methods of
the same class is mutually exclusive. Why?
Example
public class PrintThread2 extends Thread {
String name;
public PrintThread2(String name) {
this.name = name;
}
public static synchronized void print(String name) {
for (int i=1; i<500 ; i++) {
try {
Thread.sleep((long)(Math.random() * 100));
} catch (InterruptedException ie) { }
System.out.print(str);
}
}
Example (cont)
public void run() {
print(name);
}
public MoneyTransfer(
BankAccount from, BankAccount to, float amount) {
this.from = from;
this.to = to;
this.amount = amount;
}
// At one place
Runnable transaction1 =
new MoneyTransfer(aliceAccount, bobAccount, 1200);
Thread t1 = new Thread(transaction1);
t1.start();
// At another place
Runnable transaction2 =
new MoneyTransfer(bobAccount, aliceAccount, 700);
Thread t2 = new Thread(transaction2);
t2.start();
Deadlocks
t1 t2
aliceAccount bobAccount
transfer() transfer()
?
withdraw() withdraw()
deposit() deposit()
Java Locks are Reentrant
Is there a problem with the following code?
synchronized (lock) {
while (!resourceAvailable()) {
lock.wait();
}
consumeResource();
}
Producer
produceResource();
synchronized (lock) {
lock.notifyAll();
}
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
Wait/Notify Sequence
Lock Object
1. synchronized(lock){ 3. produceResource()
2. lock.wait(); 4. synchronized(lock) {
5. lock.notify();
9. consumeResource();
10. } 6.}
7. Reacquire lock
8. Return from wait()
Consumer Producer
Thread Thread
The Simpsons Scenario: SimpsonsTest
new Thread(homer).start();
new Thread(marge).start();
}
}
The Simpsons Scenario:
Homer
public class Homer implements Runnable {
CookyJar jar;
java.lang.Object
|
+----java.awt.Component
|
+----java.awt.Container
|
+----java.awt.Panel
|
+----java.applet.Applet
The simplest possible applet
TrivialApplet.java
import java.applet.Applet;
public class TrivialApplet extends Applet { }
TrivialApplet.html
<applet
code="TrivialApplet.class”
width=150 height=100>
</applet>
The simplest reasonable applet
import java.awt.*;
import java.applet.Applet;
Most HTML
HTML
tags are
containers.
HEAD BODY
A container is
<tag> to </tag>
TITLE (content)
HTML
<html>
<head>
<title> Hi World Applet </title>
</head>
<body>
<applet code="HiWorld.class”
width=300 height=200>
<param name=arraysize value=10>
</applet>
</body>
</html>
<param name=arraysize value=10>
String s = getParameter(“arraysize”);