14
News
En effet, cette API est décrite dans la
spécification JSR-166 dirigée par Doug
Lea. Elle a donc été tout naturellement
incluse dans la Java 1.5.
Cette API permet une abstraction du
modèle de thread Java incluant les
executors, un framework de thread task,
des files d’attente de threads, les timers,
les locks (atomiques ou pas) et des
primitives de synchronisation.
Ainsi la programmation de sémaphores
est facilitée. Par exemple, désormais il est
possible de faire un wait sur un sémaphore
permettant de contrôler l’accès à un bloc
de code. Les sémaphores sont plus
souples et peuvent permettre l’accès à
plusieurs threads concurrents (bien sûr,
il faut que vous testiez le lock avant de
l’acquérir dans vos threads, ça ne se fait
pas encore tout seul :)). Je vous invite à
regarder le package java.util.concurrent
pour plus d’informations :
Il était une fois RMIC
Lorsque vous faites de la programmation
RMI (Remote Method Invocation), vous
avez le mécanisme que j’avais expliqué
dans l’article « Jboss »[1] : génération
du stub côté client qui est un proxy
embarquant les fonctionnalités réseau,
transfert réseau, skeleton côté serveur
qui est la même chose que le stub mais
côté serveur.
Dans un contexte J2EE, c’est le serveur
d’application qui s’occupe de la génération
des stubs et des skeletons. Mais lorsque
vous faites du RMI hors contexte J2EE,
il vous faut générer le stub de votre côté
(le côté client). Pour cela, vous deviez
faire appel à RMIC qui était un outil de
compilation RMI.
Désormais, avec l’utilisation des proxies
dynamiques, vous n’avez plus besoin de
RMIC : les informations fournies dans le
stub peuvent désormais être découvertes
à l’exécution.
Performances, évolutivité
et management
Amélioration des
performances
On reproche souvent à Java sa lenteur
et sa consommation ressource (même si
les choses se sont beaucoup améliorées
depuis Java 1.2). Java 1.5 s’est fixé des
objectifs de performance sans équivalent
et notamment au lancement.
Une nouveauté intéressante est
l’introduction du partage des données
de classe entre JVM. Cette technologie
permet à plusieurs JVM de partager les
mêmes données read-only, mais aussi de
permettre un démarrage plus rapide en
permettant le pre-packaging des classes
bas niveau de la JVM. Ainsi les nouvelles
JVM créées utilisent des données déjà
chargées en mémoire et sont donc
plus rapides. De nouvelles options
de paramétrage du heap Java voient
également le jour dans Java 1.5.
Désormais, deux nouveaux paramètres
permettent de spécialiser le comportement
de la JVM en fonction de l’application :
Le Maximum Pause Time Goal (option
-XX:MaxGCPauseMillis=nnn
) représente
le temps d’arrêt de l’application lorsque
le Garbage Collector est appelé. Si le
Garbage Collector met plus de temps
que le Maximum Pause Time Goal
pour s’exécuter, ce dernier est arrêté et
l’application reprend la main.
Le Throughput Goal (option
-XX:
GCTimeRatio=nnn
) mesure le temps occupé
par le Garbage Collector par rapport au
temps total. Ainsi, vous pouvez limiter
le temps passé en Garbage Collection
(le ratio est calculé par
1/(1 + nnn)
).
Ainsi, si vous précisez un ratio de 19 (
-
XX:GCTimeRatio=19
), cela signifie qu’au
maximum, vous allez passer 5% du temps
d’exécution dans le Garbage Collector.
Monitoring et management
Je vous avais déjà présenté JMX (Java
Management eXtension, spécification
JSR-160) dans l’article sur JBoss.
JMX permet de monitorer et manager
des périphériques ou applications
JMX-compliants. Désormais, JMX est
directement inclus dans la JVM ce qui
vous permet de monitorer et de manager
la JVM elle-même.
Dans la plate-forme Java, le monitoring
et le management sont un des points clef
de ce qu’on appelle RAS : Reliability,
Availability, Serviceability.
Désormais, vous disposez d’une API
dédiée au monitoring et au management.
Vous pouvez donc monitorer/manager
votre JVM directement dans du code ou
en utilisant un adaptateur JMX (client
distant ou console Web).
Par exemple, nous pouvons démarrer une
JVM avec le support d’une console JMX
sur un port donné :
Une autre possibilité est de monitorer
directement dans votre code. Voilà
comment afficher l’usage détaillé du heap
de la JVM :
Profiling
Java 1.5 inclut une API de profiling
appelée JVMTI. Cette API est spécifiée
dans la JSR-163, l’objectif initial était
de refondre les interfaces de profiling.
Au final, l’API couvre beaucoup d’autres
choses comme le profiling, le debugging
et des outils d’analyse de code.
L’implémentation inclut un mécanisme
d’instrumentation du bytecode appelé
JPLIS (Java Programming Language
Instrumentation Services) qui permet à
des outils d’analyse d’ajouter du profiling
uniquement lorsque c’est nécessaire.
L’avantage de cette technique est de se
focaliser uniquement sur les analyses et
de ne pas avoir d’interférences d’outils
de profiling de la JVM. L’instrumentation
peut être générée à l’exécution ou au
chargement de classe. L’exemple suivant
crée une instrumentation qui peut charger
une version modifiée d’une classe à partir
du disque. Pour lancer ce test, exécuter
java -javaagent=myBCI BCITest
:
[1] Jean-Baptiste Onofré, « Jboss » in Linux magazine 60.
final private Semaphore s = new Semaphore(1, true);
int balanceAccount = 1000;
s.acquireUninterruptibility();
// si vous ne voulez pas de bloquage, vous pouvez utiliser
s.acquire() à la place. Ici, tant qu’on obtient pas le lock,
on attend.
try {
// on rentre en section critique, ce block est locké
// et donc protégé
balanceAccount = balanceAccount + 10;
}
finally {
s.release(); // on rend le lock disponible
}
java -Dcom.sun.management.jmxremote.port=5001 -Dcom.sun.
management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.
authenticate=false -jar Java2Demo.jar
import java.lang.management.*;
import java.util.*;
public class MemoryUsage {
public static void main(String args[]) {
List<MemoryPoolMXBean> pools = ManagementFactory.
getMemoryPoolMXBeans();
for(MemoryPoolMXBean p: pools) {
System.out.println(„Memory type = „ + p.getType() + „ /
Memory usage = „ + p.getUsage());
}
}
}