public class T implements Runnable { public void run() { } } public static void main(String[] args) { Thread t1 = new Thread(new T()); t1.start(); }
public class T extends Thread { public void run() { } } public static void main(String[] args) { T t1 = new T(); t1.start(); }
Une FutureTask
doit renvoyer un type. Mettre Void
et return null
si le type de retour n'est pas utilisé.
FutureTask
s'exécute depuis un Executor
et la valeur de retour est récupérée via la méthode bloquante get
.
Quand une exception est générée, elle n'est pas remontée au thread principale. Elle est transformée en une ExecutionException
qui sera générée lors de l'appel à get
.
import java.util.concurrent.FutureTask; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ExecutionException; public class MyClass { public static void main(String args[]) { FutureTask<Void> futureTask = new FutureTask<Void> (() -> { throw new IOException("OUPS"); }); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(futureTask); try { futureTask.get(); } catch (InterruptedException e) { } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("OK"); System.out.println("OK2"); executor.shutdown(); } }
Sortie standard :
OK OK2 java.util.concurrent.ExecutionException: java.io.IOException: OUPS at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) at MyClass.main(MyClass.java:15) Caused by: java.io.IOException: OUPS at MyClass.lambda$main$0(MyClass.java:10) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)
Si l'exception doit être remontée au thread principale, il faut créer une classe qui hérite de FutureTask
et surchargée la méthode done()
, appeler le get()
avec le try/catch associé et générer une autre exception (AssertionError
par exemple).
import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; public class MyClass { public static class SecuredFutureTask<V> extends FutureTask<V> { public SecuredFutureTask(Callable<V> callable) { super(callable); } @Override protected void done() { try { get(); } catch (ExecutionException | InterruptedException e) { throw new AssertionError(e); } } } public static void main(String args[]) { FutureTask<Void> futureTask = new SecuredFutureTask<Void>(() -> { throw new IOException("OUPS"); }); ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(futureTask); System.out.println("OK"); executor.shutdown(); } }
Sortie standard :
OK Exception in thread "pool-1-thread-1" java.lang.AssertionError: java.util.concurrent.ExecutionException: java.io.IOException: OUPS at MyClass$SecuredFutureTask.done(MyClass.java:19) at java.base/java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:381) at java.base/java.util.concurrent.FutureTask.setException(FutureTask.java:250) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:269) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) Caused by: java.util.concurrent.ExecutionException: java.io.IOException: OUPS at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) at MyClass$SecuredFutureTask.done(MyClass.java:17) ... 6 more Caused by: java.io.IOException: OUPS at MyClass.lambda$main$0(MyClass.java:25) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ... 3 more
class C { synchronized void p(){ } }
est équivalent à
class C { void p() { synchronized (this){ } } }
Le concept consiste à poser un lock sur une instance ou sur une classe.
Concurrency in JDK 5.0 Archive au 30/09/2019, version du 23/11/2004
Barrière en attente d'un signal.
import java.util.concurrent.Semaphore; public class MyClass { public static void main(String args[]) { Semaphore semaphoreAcquisitionReady = new Semaphore(0); new Thread(() -> { try { Thread.sleep(50); } catch (InterruptedException e) {} System.out.println("BEFORE release"); semaphoreAcquisitionReady.release(); System.out.println("AFTER release"); }).start(); System.out.println("BEFORE acquire"); try { semaphoreAcquisitionReady.acquire(); } catch (InterruptedException e) {} System.out.println("AFTER acquire"); semaphoreAcquisitionReady.release(); } }
Sortie standard.
BEFORE acquire BEFORE release AFTER release AFTER acquire
Par défaut, le nom d'un thread est Thread-0
/ Thread-1
. Si le thread tourne dans un pool : pool-1-thread-1
.
Dans le cas des threads, cela se fait directement depuis le constructeur.
new Thread(() -> {}, "Nom du thread").start();
Dans le cas de Runnable
qui se lancent dans un pool de threads, il faut modifier le nom directement dans la méthode exécutée par le thread.
new FutureTask<>(() -> { Thread.currentThread().setName("Nom du thread"); });