Computer
Science
School
Dr. Eliahu Khalastchi
2017
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Introduction
By now, you know how to program threads
But in a very basic level that matches low-level implementations
For higher-level code, we need advanced tools
Tools that will hide the threads logic from us
Makes it easier for us to control threads
Mostly are from [Link]
introduced in java 1.5
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
With simpler tools…
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Scheduling
We can use sleep() & wait() to influence thread scheduling
Blocked
Scheduler choice
Ready Queue
End of Time slice Running
Born Dead
[Link](x)
Sleep
[Link]()
Wait
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Scheduling Tasks
public class Ping implements Runnable{
We want an ordered
public void run(){while(true)[Link]("ping");} “ping-pong” sequence
} Half a second apart
public class Pong implements Runnable{ Does this code meet the
public void run(){while(true)[Link]("pong");} demands?
}
public static void main(String[] args) {
Ping ping=new Ping();
Pong pong=new Pong();
Thread t=new Thread(ping,"thread 1");
Thread t1=new Thread(pong,"thread 2");
[Link]();
[Link]();
}
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Scheduling Tasks
Here is a solution using sleep()
public class Ping implements Runnable{ public static void main(String[] args) throws InterruptedException {
public void run(){ Ping ping=new Ping();
while(true){ Pong pong=new Pong();
[Link]("ping"); Thread t=new Thread(ping,"thread 1");
try {[Link](1000);} Thread t1=new Thread(pong,"thread 2");
catch (InterruptedException e) {} [Link]();
} [Link](500); // the main sleeps 0.5 sec
} [Link]();
} }
// pong is the same…
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Scheduling Tasks – with a simple Timer!
import [Link];
import [Link];
public class ThreadTest {
private static class Ping extends TimerTask{
public void run(){[Link]("ping");}
}
Canceling tasks:
private static class Pong extends TimerTask{
int i;
public void run(){[Link]("pong");}
} while((i=[Link]())!=13);
public static void main(String[] args){ [Link](); // canceled task
Ping ping=new Ping(); [Link](); // t continues…
Pong pong=new Pong(); [Link](); // t is cancled
Timer t=new Timer();
[Link](ping, 0, 1000);
[Link](pong, 500, 1000);
}
}
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
With faster / none-blocking locks
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Using Synchronized is slow…
public class Count { public static void main(String[] args) {
private int count; Count c=new Count();
public void setCount(int x){count=x;} [Link](0);
public int getCount(){return count;} CountUpdater ca=new CountUpdater(c);
public synchronized void update(){count++;} Thread t=new Thread(ca);
} Thread t1=new Thread(ca);
long time=[Link]();
public class CountUpdater implements Runnable{ [Link]();
Count c; [Link]();
public CountUpdater(Count c){this.c=c;} [Link]();
public void run(){ [Link]();
for(int i=0;i<100000000; [Link](),i++); [Link]([Link]());
} long duration=([Link]()-time)/1000;
} [Link](duration);
}
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Using Atomic Variables
import [Link]; public static void main(String[] args) {
public class Count { Count c=new Count();
AtomicInteger count = new AtomicInteger(0); [Link](0);
public void setCount(int x){[Link](x);} CountUpdater ca=new CountUpdater(c);
public int getCount(){return [Link]();} Thread t=new Thread(ca);
public void update(){ Thread t1=new Thread(ca);
[Link]();// ++count long time=[Link]();
} [Link]();
} [Link]();
public class CountUpdater implements Runnable{ [Link]();
Count c; [Link]();
public CountUpdater(Count c){this.c=c;} [Link]([Link]());
public void run(){ long duration=([Link]()-time)/1000;
for(int i=0;i<100000000; [Link](),i++); [Link](duration);
} }
}
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
And how to avoid it…
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Deadlock Example
Object R=new Object();// readers lock
Object W=new Object();// writers lock
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
synchronized (W) { synchronized (R) {
// do the writing... // do the reading...
synchronized (R) { synchronized (W) {
// do some reading... // do some writing...
} }
// do more writing... // do more reading...
} }
} }
}).start(); }).start();
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Deadlock avoidance with tryLock()
Import [Link]; public void run() {
boolean w=[Link]();
ReentrantLock W=new ReentrantLock(); boolean r=[Link]();
ReentrantLock R=new ReentrantLock(); try{
if(w && r){
// do the writing...
• reentrantLock allows to use tryLock(); // do some reading...
• It returns true / false // do more writing...
• Instead of just blocking like synchronized… } else{
// try again later...
• Only if we manage to lock both locks }
• We do the reading & writing }finally{
• Else, we try again later if(w) [Link]();
if(r) [Link]();
• Finally, we unlock whatever lock we may have locked }
}
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Executing tasks with different executors!
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Executor Interface
So far we used threads with Runnable’s
public void run() method
There is a direct attachment between the task and the thread that runs it…
Sometimes we want to decouple these two
Controlling the number of threads
Scheduling tasks
etc
interface Executor {
void execute(Runnable r);
Therefore an Executor Interface was created }
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Executor Implementations Example
interface Executor {
void execute(Runnable r);
}
class DirectExecutor implements Executor{ class ThreadPerTaskExecutor implements Executor{
public void execute(Runnable r) { public void execute(Runnable r) {
[Link](); new Thread(r).start();
} }
} }
And if we wanted to control the number of threads?
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Thread Pool
We can use a queue
Each execute puts the runnable at the end
Only the first n are polled out of the queue
They are ran via a thread
When a task has finished, another is polled
This is called a Thread Pool
It is commonly used to control the number of threads, clients etc…
Strong and flexible thread pools are already implemented for us
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Thread Pools Example
public class RunnableTask1 implements Runnable{ import [Link];
public void run(){ import [Link];
[Link]("task1 started"); import [Link];
try { [Link](10000);} //...
catch (InterruptedException e) {} public static void main(String[] args) {
[Link]("task1 finished"); ExecutorService executor =
} [Link]();
} [Link] (new RunnableTask1 ());
// RunnableTask2 & RunnableTask3 are the same… [Link] (new RunnableTask2 ());
[Link] (new RunnableTask3 ());
Executors class has a factory of task1 started }
thread pools. SingleThreadExecutor task1 finished
allows only one thread to be ran at task2 started
a time. What would be the output? task2 finished
task3 started
task3 finished
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Thread Pools Example
public class RunnableTask1 implements Runnable{ import [Link];
public void run(){ import [Link];
[Link]("task1 started"); import [Link];
try { [Link](10000);} //...
catch (InterruptedException e) {} public static void main(String[] args) {
[Link]("task1 finished"); ExecutorService executor =
} [Link](2);
} [Link] (new RunnableTask1 ());
// RunnableTask2 & RunnableTask3 are the same… [Link] (new RunnableTask2 ());
[Link] (new RunnableTask3 ());
How about now? task1 started }
task2 started
task1 finished
task2 finished
task3 started
task3 finished
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Thread Pools Example
public class RunnableTask1 implements Runnable{ import [Link];
public void run(){ import [Link];
[Link]("task1 started"); import [Link];
try { [Link](10000);} //...
catch (InterruptedException e) {} public static void main(String[] args) {
[Link]("task1 finished"); ExecutorService executor =
} [Link]();
} [Link] (new RunnableTask1 ());
// RunnableTask2 & RunnableTask3 are the same… [Link] (new RunnableTask2 ());
[Link] (new RunnableTask3 ());
How about now? task1 started }
task2 started
task3 started
task1 finished
task3 finished
task2 finished
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Callable
Runnabler’s run() method
interface Callable<V> {
Cannot return a value
V call() throws Exception;
Cannot throw an exception
}
A Callable Interface can
ExecutorService can
execute(Runnable r); // as we have seen
submit(Callable c);
It puts the callable in the thread pool and immediately returns
What can be returned by submit?
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
The problem
public class MyCallable implements Callable<Worker>{
Worker call() throws Exception{
// after 10 minutes or so…
return someWorker;
}
}
ExecutorService executor = Executors. newFixedThreadPool (2);
___________ = [Link] (new MyCallable ());
1. submit() was written years ago… Worker was created just now…
2. submit() should return a value now! And not in 10 minutes
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
The Solution – Future! Future <V>
V value;
Future is a holder for a value of type <V> set(V v);
V get();
The submit method returns immediately an instance of Future
Future<V> submit(Callable<V> callable);
We should define the same V in the Callable and the Future
When the Callable’s call() returns <V> it is set in the instance of Future
Only then, we may get <V>
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
The Solution – Future! Future <V>
V value;
public class MyCallable implements Callable<Worker>{ set(V v);
Worker call() throws Exception{
V get();
// after 10 minutes or so…
return someWorker;
}
}
ExecutorService executor = Executors. newFixedThreadPool (2);
Future<Worker> f = [Link] (new MyCallable ());
Worker w = [Link](); // waits for the call() to return
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Thread Safe Containers
Most of [Link] containers are not thread safe
Because synchronize slows performance
They could be wrapped with synchronized decorators
Only when we must, we’ll pay with performance
Map<String,Integer> hm =
[Link](
new HashMap<String,Integer>());
Decorator Pattern!
Every method is implemented with synchronized
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Thread Safe Containers
[Link] introduced Thread Safe containers,
that also provides good performance!
ArrayBlockingQueue<E>
ConcurrentHashMap<K,V>
ConcurrentLinkedQueue<E>
etc…
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©
Computer
Science
School
Now you know how to handle the problems…
private void runServer()throws Exception {
ServerSocket server=new ServerSocket(port);
[Link](1000);
while(!stop){
try{
Socket aClient=[Link](); // blocking call
new Thread(new Runnable() { //WOW! we should control the number of threads!
public void run() {
try {
[Link]([Link](), [Link]());
[Link]().close();
[Link]().close();
[Link]();
} catch (IOException e) {/*...*/}
}
}).start();
}catch(SocketTimeoutException e) {/*...*/}
}
[Link](); //WOW! we should wait for all threads before closing!
}
Advanced Software Development 2, Dr. Eliahu Khalastchi, 2017 ©