Download Thread Pool

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Advanced Tools for MultiThreads Programming
Avshalom Elmalech
Eliahu Khalastchi
2010
Introduction



Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
By now, you know how to program threads
But in a very basic level that matches lowlevel 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 java.util.concurrent
introduced in java 1.5
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Scheduling Tasks
public class ThreadTest {

private static class Ping implements Runnable{
public void run(){while(true)System.out.println("ping");}
}
private static class Pong implements Runnable{
public void run(){while(true)System.out.println("pong");}
}
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");
t.start();
t1.start();
}
}


We want an
ordered “pingpong” sequence
Half a second apart
Does this code
meet the
demands?
Scheduling Tasks


Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
We already saw a solution using wait()
Here is a solution using sleep()
public class ThreadTest {
public static void main(String[] args) throws
private static class Ping implements Runnable{
InterruptedException {
public void run(){
Ping ping=new Ping();
while(true){
Pong pong=new Pong();
System.out.println("ping");
Thread t=new Thread(ping,"thread 1");
try {Thread.sleep(1000);}
Thread t1=new Thread(pong,"thread 2");
catch (InterruptedException e) {}
t.start();
}
long time2,time=System.currentTimeMillis();
}
while((time2=System.currentTimeMillis())-time<500);
}
t1.start();
private static class Pong implements Runnable{
}}
…
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Scheduling Tasks

A far more simple way – use a timer!
import java.util.Timer;
import java.util.TimerTask;
public class ThreadTest {
private static class Ping extends TimerTask{
public void run(){System.out.println("ping");}
}
private static class Pong extends TimerTask{
public void run(){System.out.println("pong");}
}
public static void main(String[] args){
Ping ping=new Ping();
Pong pong=new Pong();
Timer t=new Timer();
t.scheduleAtFixedRate(ping, 0, 1000);
t.scheduleAtFixedRate(pong, 500, 1000);
}
}
Canceling tasks:
int i;
while((i=System.in.read())!=13);
ping.cancel(); // canceled task
pong.cancel(); // t continues…
t.cancel(); // t is cancled
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Atomic objects
public class Count {
private int count;
public void setCount(int x){count=x;}
public class ThreadTest {
private static class CountAdapter implements Runnable{
Count c;
public CountAdapter(Count c){
public int getCount(){return count;}
this.c=c;
}
public synchronized void
update(){count++;}
public void run(){
for(int i=0;i<100000000;i++)
c.update();
}
}


Last time we
synchronized the
update() method,
since count++ is an
atomic action
It took about 46
seconds to complete
}
public static void main(String[] args) {
Count c=new Count();
c.setCount(0);
CountAdapter ca=new CountAdapter(c);
Thread t=new Thread(ca);
Thread t1=new Thread(ca);
long time=System.currentTimeMillis();
t.start();
t1.start();
while(t.isAlive() || t1.isAlive());
System.out.println(c.getCount());
System.out.println((System.currentTimeMillis()-time)/1000);
}}
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Atomic objects
import
java.util.concurrent.atomic.AtomicInteger;
public class ThreadTest {
private static class CountAdapter implements Runnable{
Count c;
public class Count {
public CountAdapter(Count c){
private AtomicInteger count = new
AtomicInteger(0);
public
void setCount(int x){count.set(x);}
public int getCount(){return count.get();}
this.c=c;
}
public void run(){
for(int i=0;i<100000000;i++)
c.update();
public void update(){
}
count.incrementAndGet();// count++
}
}
public static void main(String[] args) {
}
Count c=new Count();



We use an AtomicInteger
instead of int
There is no synchronized
Took only 6 seconds to
complete
(with the desired result)
c.setCount(0);
CountAdapter ca=new CountAdapter(c);
Thread t=new Thread(ca);
Thread t1=new Thread(ca);
long time=System.currentTimeMillis();
t.start();
t1.start();
while(t.isAlive() || t1.isAlive());
System.out.println(c.getCount());
System.out.println((System.currentTimeMillis()-time)/1000);
}}
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Deadlock Example
Since in dates the topic is usually
about “HA and DA” an icebreaker
protocol was devised:
public class Friend {
private String name;
public Friend(String name){this.name = name;}
public String getName(){return this.name;}
public synchronized void sayHA(Friend date) {
System.out.format("%s says HA to %s%n",this.name, date.getName());
The first person says “ha” and the
other should reply “da”
date.sayDA(this);
}
public synchronized void sayDA(Friend date) {
This is an implementation of the
protocol.
System.out.format("%s says DA to %s%n",this.name,date.getName());
}
}
public class DeadLock {
Will it work?
private static class FriendRun implements Runnable{
private Friend me,date;
public FriendRun(Friend m,Friend d){ me=m;date=d;}
public void run(){ me.sayHA(date); }
Alice says HA to Bob
}
public static void main(String[] args) {
Bob says HA to Alice
Friend alice = new Friend("Alice");
Friend bob = new Friend("Bob");
Thread t=new Thread(new FriendRun(alice,bob));
Thread t1=new Thread(new FriendRun(bob,alice));
t.start();
t1.start();
}}
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Deadlock Example
public class Friend {
A
t
private String name;
public Friend(String name){this.name = name;}
B
t1
public String getName(){return this.name;}
public synchronized void sayHA(Friend date) {
t
FR
A
System.out.format("%s says HA to %s%n",this.name, date.getName());
B
date.sayDA(this);
}
public synchronized void sayDA(Friend date) {
Start()
t1
FR
B
A
System.out.format("%s says DA to %s%n",this.name,date.getName());
}
}
A.sayHA(B)
A is locked by t
t: B.sayDA(A)
Impossible, B is
locked by t1
A.sayHa(B) will
not finish, A
remains locked!
Start()
public class DeadLock {
private static class FriendRun implements Runnable{
B.sayHA(A)
B is locked by t1
private Friend me,date;
public FriendRun(Friend m,Friend d){ me=m;date=d;}
public void run(){ me.sayHA(date); }
t1: A.sayDA(B)
Impossible, A is
locked by t
B.sayHa(A) won’t
finish, B remains
locked!
}
public static void main(String[] args) {
Friend alice = new Friend("Alice");
Friend bob = new Friend("Bob");
Thread t=new Thread(new FriendRun(alice,bob));
Thread t1=new Thread(new FriendRun(bob,alice));
t.start();
t1.start();
Neither side has finished saying HA
}}
Solving deadlocks with locks
import java.util.concurrent.locks.Lock;
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
public void sayHA(Friend date) {
import java.util.concurrent.locks.ReentrantLock;
if(iCanLockBoth(date)){
public class Friend {
try{
private String name;
System.out.format("%s says HA to %s%n",this.name,date.getName());
date.sayDA(this);
} finally{
protected Lock lock = new ReentrantLock();
lock.unlock();
date.lock.unlock();
public Friend(String name){this.name = name;}
}
public String getName(){return this.name;}
} else
public boolean iCanLockBoth(Friend date) {
Boolean myLock = false;
Boolean yourLock = false;
try {
myLock=lock.tryLock();
yourLock=date.lock.tryLock();
} finally {
if (!(myLock&&yourLock)) {
System.out.format("%s started to say HA but realized %s already
started",name,date.getName());
}
iCanLockBoth will return true only if we managed to
lock both locks (by the same thread). Only then, will
the friend say “ha” and call the other to say “da”,
otherwise it will say it couldn’t say ha…
if (myLock) lock.unlock();
if (yourLock) date.lock.unlock();
}
}
Alice says HA to Bob
}
Bob says DA to Alice
return myLock&&yourLock;
Bob started to say HA but realized Alice already started
Executor Interface



So far we used threads with Runnable’s
public void run() method
There was a direct attachment between the
task and the thread that runs it…
Sometimes we want to decouple these two




Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Controlling the number of threads
Scheduling tasks
etc
Therefore an Executor Interface was created
Executor Interface

It has one method:


Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
public void execute(Runnable r)
We can implement it as we wish
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
Executor Interface

We can also use a queue







Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
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
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Thread Pools
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
public static void main(String[] args) {
import java.util.concurrent.Executors;
Executor executor = Executors.newSingleThreadExecutor();
public class ThreadTest3 {
executor.execute (new RunnableTask1 ());
executor.execute (new RunnableTask2 ());
private static void delay(long ms){
try { Thread.sleep(ms);}
executor.execute (new RunnableTask3 ());
catch (InterruptedException e) {}
((ExecutorService) executor).shutdown();
}
}
private static class RunnableTask1 implements Runnable{
public void run(){
System.out.println("task1 started");
delay(10000);
System.out.println("task1 finished");
}
}…
Executors class has a factory of thread
pools, a SingleThreadExecutor allows
only one thread to be ran at a time
What would be the output?
task1 started
task1 finished
task2 started
task2 finished
task3 started
task3 finished
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Thread Pools
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
public static void main(String[] args) {
import java.util.concurrent.Executors;
Executor executor = Executors. newFixedThreadPool (2);
public class ThreadTest3 {
executor.execute (new RunnableTask1 ());
executor.execute (new RunnableTask2 ());
private static void delay(long ms){
try { Thread.sleep(ms);}
executor.execute (new RunnableTask3 ());
catch (InterruptedException e) {}
((ExecutorService) executor).shutdown();
}
}
private static class RunnableTask1 implements Runnable{
public void run(){
How about now?
System.out.println("task1 started");
delay(10000);
System.out.println("task1 finished");
}
}…
task1 started
task2 started
task1 finished
task2 finished
task3 started
task3 finished
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Thread Pools
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
public static void main(String[] args) {
import java.util.concurrent.Executors;
Executor executor = Executors. newCachedThreadPool();
public class ThreadTest3 {
executor.execute (new RunnableTask1 ());
executor.execute (new RunnableTask2 ());
private static void delay(long ms){
try { Thread.sleep(ms);}
executor.execute (new RunnableTask3 ());
catch (InterruptedException e) {}
((ExecutorService) executor).shutdown();
}
}
private static class RunnableTask1 implements Runnable{
public void run(){
How about now?
System.out.println("task1 started");
delay(10000);
System.out.println("task1 finished");
}
}…
task1 started
task2 started
task3 started
task1 finished
task3 finished
task2 finished
Callable

Runnabler’s run() method



Cannot return a value
Cannot throw an exeption
A Callable Interface can
Interface Callable<V>
V call() throws Exception;
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Future

Executors can submit a Callable


Using the submit(Callable<V> c) method
But what should submit return??


Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
c.call() return V, that could be anything…
Submit return a special object called Future


Future<V> submit(Callable<V> c)
V should be the same V of the Callable
Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Callable, Future
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
task1 started
import java.util.concurrent.Executors;
task2 started
import java.util.concurrent.Future;
task3 started
public class ThreadTest3 {
task1 finished
private static void delay(long ms){
try { Thread.sleep(ms);}
task2 finished
catch (InterruptedException e) {}
task3 finished
}
private static class CallableTask implements Callable<Integer>{
Integer i;
public CallableTask(int i){
public static void main(String[] args) throws
InterruptedException, ExecutionException {
this.i=new Integer(i);
ExecutorService executor = Executors.newCachedThreadPool();
}
Future<Integer> futures[]=new Future[3];
public Integer call() throws Exception {
for(int i=0;i<3;i++)
System.out.printf("task%d started\n",i);
futures[i]=executor.submit (new CallableTask(i+1));
delay(10000);
executor.shutdown();
return i;
for(int i=0;i<3;i++)
}
}
System.out.printf("task%d finished\n",futures[i].get());
}
Thread Safe Containers

Most of java.util containers are not thread
safe


Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
Because synchronize slows performance
They could be wrapped with synchronized
decorators

Only when we must, we’ll pay with performance
private Map<String,Integer> hm =
Collections.synchronizedMap( new HashMap<String,Integer>());
Thread Safe Containers

Introduction
Scheduling Tasks
Atomic objects
Deadlock avoidance
Thread Pools
Callable, Future
Thread safe containers
java.util.concurrent introduced Thread Safe
containers, that also provides good
performance!




ArrayBlockingQueue<E>
ConcurrentHashMap<K,V>
ConcurrentLinkedQueue<E>
etc…
Related documents