 |
 |
14) Les Threads multiples |
|
 |
|
Texte original |
 |
Traducteur :
Cédric Babault |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
///:Continuing
/////////// Blocking via wait() ///////////
class WaitNotify1 extends Blockable {
public WaitNotify1(Container c) { super(c); }
public synchronized void run() {
while(true) {
i++;
update();
try {
wait(1000);
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
}
}
}
class WaitNotify2 extends Blockable {
public WaitNotify2(Container c) {
super(c);
new Notifier(this);
}
public synchronized void run() {
while(true) {
i++;
update();
try {
wait();
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
}
}
}
class Notifier extends Thread {
private WaitNotify2 wn2;
public Notifier(WaitNotify2 wn2) {
this.wn2 = wn2;
start();
}
public void run() {
while(true) {
try {
sleep(2000);
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
synchronized(wn2) {
wn2.notify();
}
}
}
} ///:Continued
|
 |
///:Continuing /////////// Blocqué via wait() /////////// class WaitNotify1 extends Blockable { public WaitNotify1(Container c) { super(c); } public synchronized void run() { while(true) { i++; update(); try { wait(1000); } catch(InterruptedException e) { System.err.println("Interrupted"); } } } }
class WaitNotify2 extends Blockable { public WaitNotify2(Container c) { super(c); new Notifier(this); } public synchronized void run() { while(true) { i++; update(); try { wait(); } catch(InterruptedException e) { System.err.println("Interrupted"); } } } }
class Notifier extends Thread { private WaitNotify2 wn2; public Notifier(WaitNotify2 wn2) { this.wn2 = wn2; start(); } public void run() { while(true) { try { sleep(2000); } catch(InterruptedException e) { System.err.println("Interrupted"); } synchronized(wn2) { wn2.notify(); } } } } ///:Continued
|
 |
 |
 |
wait( ) is typically used
when you’ve gotten to the point where you’re waiting for some other
condition, under the control of forces outside your thread, to change and you
don’t want to idly wait by inside the thread. So wait( )
allows you to put the thread to sleep while waiting for the world to change, and
only when a notify( ) or notifyAll( ) occurs does the
thread wake up and check for changes. Thus, it provides a way to synchronize
between threads.
|
 |
wait() est typiquement utilisé quand vous êtes
arrivé à un point où vous attendez qu'une autre condition, sous le
contrôle de forces extérieures à votre thread, change et que vous ne voulez pas
attendre activement à l'intérieur du thread. Donc wait() vous autorise
à mettre votre thread en sommeil en attendant que le monde change, et c'est seulement quand
un notify() ou notifyAll() arrive que le thread se réveille et controle les
changements. Ainsi, on dispose d'un moyen de synchronization entre les threads.
|
 |
 |
 |
Blocking on I/O
|
 |
Bloqué sur I/O
|
 |
 |
 |
If a stream is waiting for some I/O
activity, it will automatically block. In the following portion of the example,
the two classes work with generic Reader and
Writer objects, but in the test framework a
piped stream will be set up to
allow the two threads to safely pass data to each other (which is the purpose of
piped streams).
|
 |
Si un flux est en attente de l'activité d'une I/O, il se bloquera
automatiquement. Dans la portion suivante de l'exemple, les deux classes travaillent avec les
objets génériques Reader et Writer, mais dans le framework de test un
piped stream sera créé afin de permettre au deux threads de se passer des
données de façon sûre (ce qui est le but des piped streams).
|
 |
 |
 |
The Sender puts data into the
Writer and sleeps for a random amount of time. However, Receiver
has no sleep( ), suspend( ), or wait( ). But
when it does a read( ) it automatically blocks when there is no more
data.
|
 |
Le Sender place des données dans le Writer et s'endort
pour un temps tiré au hasard. Cependant Receiver n'a pas de sleep(),
suspend(), ou wait(). Mais quand il appelle read() il se bloque
automatiquement quand il n'y a pas d'autre données.
|
 |
 |
 |
///:Continuing
class Sender extends Blockable { // send
private Writer out;
public Sender(Container c, Writer out) {
super(c);
this.out = out;
}
public void run() {
while(true) {
for(char c = 'A'; c <= 'z'; c++) {
try {
i++;
out.write(c);
state.setText("Sender sent: "
+ (char)c);
sleep((int)(3000 * Math.random()));
} catch(InterruptedException e) {
System.err.println("Interrupted");
} catch(IOException e) {
System.err.println("IO problem");
}
}
}
}
}
class Receiver extends Blockable {
private Reader in;
public Receiver(Container c, Reader in) {
super(c);
this.in = in;
}
public void run() {
try {
while(true) {
i++; // Show peeker it's alive
// Blocks until characters are there:
state.setText("Receiver read: "
+ (char)in.read());
}
} catch(IOException e) {
System.err.println("IO problem");
}
}
} ///:Continued
|
 |
///:Continuing class Sender extends Blockable { color="#009900">// envoie private Writer out; public Sender(Container c, Writer out) { super(c); this.out = out; } public void run() { while(true) { for(char c = 'A'; c <= 'z'; c++) { try { i++; out.write(c); state.setText("Sender sent: " + (char)c); sleep((int)(3000 * Math.random())); } catch(InterruptedException e) { System.err.println("Interrupted"); } catch(IOException e) { System.err.println("IO problem"); } } } } }
class Receiver extends Blockable { private Reader in; public Receiver(Container c, Reader in) { super(c); this.in = in; } public void run() { try { while(true) { i++; // Montre que peeker est en vie // Bloque jusqu'à ce que les caractères soient là: state.setText("Receiver read: " + (char)in.read()); } } catch(IOException e) { System.err.println("IO problem"); } } } ///:Continued
|
 |
 |
 |
Both classes also put information into
their state fields and change i so the Peeker can see that
the thread is running.
|
 |
Les deux classes placent également des informations dans leurs
champs state et change i afin que le Peeker puisse voir que le thread
tourne.
|
 |
 |
 |
Testing
|
 |
Tester
|
 |
 |
 |
The main applet class is surprisingly
simple because most of the work has been put into the Blockable
framework. Basically, an array of Blockable objects is created, and since
each one is a thread, they perform their own activities when you press the
“start” button. There’s also a button and
actionPerformed( ) clause to stop all of the Peeker objects,
which provides a demonstration of the alternative to the deprecated (in Java 2)
stop( ) method of Thread.
|
 |
La classe principale de l'applet est étonnamment simple parce la
majorité du travail a été mis dans le framework Blockable. En fait, un
tableau d'objets Blockable est créé, et puisque chacun est un thread, il
réalise leur propre activité quand vous pressez le bouton
« start ». Il y a aussi un bouton et une clause actionPerformed() pour
stopper tout les objets Peeker, qui donne une démonstration de de l'alternative
à la méthode dépréciée stop() de
Thread.
|
 |
 |
 |
To set up a connection between the
Sender and Receiver objects, a PipedWriter and
PipedReader are created. Note that the PipedReader in must
be connected to the PipedWriter out via a constructor argument.
After that, anything that’s placed in out can later be extracted
from in, as if it passed through a pipe (hence the name). The in
and out objects are then passed to the Receiver and Sender
constructors, respectively, which treat them as Reader and Writer
objects of any type (that is, they are upcast).
|
 |
Pour établir la connexion entre les objets Sender et
Receiver, un PipedWriter et un PipedReader sont créés. Notez que
le PipedReader in doit être connecté au PipedWriter out
via un argument du constructeur. Après ça, les données placées dans
out peuvent être extraites de in, comme si elles passaient dans un tube
(d'où le nom) ([NDT: un pipe est un tube en anglais]). Les objets in et
out sont alors passés respectivement aux constructeurs de Receiver et
Sender, qui les traitent comme des objets Reader et Writer (ils sont
upcast).
|
 |
 |
 |
The array of Blockable references
b is not initialized at its point of definition because the piped streams
cannot be set up before that definition takes place (the need for the try
block prevents this).
|
 |
Le tableau de références Blockable b n'est pas
initialisé à son point de définition parce que les piped streams ne peuvent
pas être établis avant cette définition (l'utilisation du bloc try
évite cela).
|
 |
 |
 |
///:Continuing
/////////// Testing Everything ///////////
public class Blocking extends JApplet {
private JButton
start = new JButton("Start"),
stopPeekers = new JButton("Stop Peekers");
private boolean started = false;
private Blockable[] b;
private PipedWriter out;
private PipedReader in;
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(!started) {
started = true;
for(int i = 0; i < b.length; i++)
b[i].start();
}
}
}
class StopPeekersL implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Demonstration of the preferred
// alternative to Thread.stop():
for(int i = 0; i < b.length; i++)
b[i].stopPeeker();
}
}
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
out = new PipedWriter();
try {
in = new PipedReader(out);
} catch(IOException e) {
System.err.println("PipedReader problem");
}
b = new Blockable[] {
new Sleeper1(cp),
new Sleeper2(cp),
new SuspendResume1(cp),
new SuspendResume2(cp),
new WaitNotify1(cp),
new WaitNotify2(cp),
new Sender(cp, out),
new Receiver(cp, in)
};
start.addActionListener(new StartL());
cp.add(start);
stopPeekers.addActionListener(
new StopPeekersL());
cp.add(stopPeekers);
}
public static void main(String[] args) {
Console.run(new Blocking(), 350, 550);
}
} ///:~
|
 |
///:Continuing /////////// Test de tout /////////// public class Blocking extends JApplet { private JButton start = new JButton("Start"), stopPeekers = new JButton("#004488">"Stop Peekers"); private boolean started = false; private Blockable[] b; private PipedWriter out; private PipedReader in; class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(!started) { started = true; for(int i = 0; i < b.length; i++) b[i].start(); } } } class StopPeekersL implements ActionListener { public void actionPerformed(ActionEvent e) { // Demonstration de la meilleure // alternative à Thread.stop(): for(int i = 0; i < b.length; i++) b[i].stopPeeker(); } } public void init() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); out = new PipedWriter(); try { in = new PipedReader(out); } catch(IOException e) { System.err.println("PipedReader problem"); } b = new Blockable[] { new Sleeper1(cp), new Sleeper2(cp), new SuspendResume1(cp), new SuspendResume2(cp), new WaitNotify1(cp), new WaitNotify2(cp), new Sender(cp, out), new Receiver(cp, in) }; start.addActionListener(new StartL()); cp.add(start); stopPeekers.addActionListener( new StopPeekersL()); cp.add(stopPeekers); } public static void main(String[] args) { Console.run(new Blocking(), 350, 550); } } ///:~
|
 |
 |
 |
In init( ), notice the loop
that moves through the entire array and adds the state and
peeker.status text fields to the page.
|
 |
Dans init(), notez la boucle qui parcourt la totalité du
tableau et ajoute les champs state et peeker.status à la page.
|
 |
 |
 |
When the Blockable threads are
initially created, each one automatically creates and starts its own
Peeker. So you’ll see the Peekers running before the
Blockable threads are started. This is important, as some of the
Peekers will get blocked and stop when the Blockable threads
start, and it’s essential to see this to understand that particular aspect
of
blocking.
|
 |
Quand les threads Blockable sont initialement créés,
chacune crée et démarre automatiquement son propre Peeker. Donc vous verrez
les Peekers tournés avant que les threads Blockable ne démarrent. C'est
important, puisque certains des Peekers seront bloqués et stoperont quand les threads
Blockable démarreront, et c'est essentiel de voir et de comprendre cet aspect
particulier du blocage.
|
 |
 |
 |
Deadlock
|
 |
Interblocage [Deadlock]
|
 |
 |
 |
Because threads can become blocked
and because objects can have synchronized methods that prevent
threads from accessing that object until the synchronization lock is released,
it’s possible for one thread to get stuck waiting for another thread,
which in turn waits for another thread, etc., until the chain leads back to a
thread waiting on the first one. You get a continuous loop of threads waiting on
each other and no one can move. This is called deadlock. The claim is
that it doesn’t happen that often, but when it happens to you it’s
frustrating to debug.
|
 |
Puisse que les threads peuvent être bloqués et puisse
que les objets peuvent avoir des méthodes synchronized qui empêchent les
threads d'accéder à cet objet jusqu'à ce que le verrou de synchronisation soit
libéré, il est possible pour un thread de rester coincé attendant un autre
thread, qui à son tour attend un autre thread, etc., jusqu'à ce que la chaîne
ramène à un thread en attente sur le premier. Vous obtenez une boucle continue de
threads s'attendant les uns les autres et aucun ne peut bouger. C'est ce qu'on appelle un
interblocage (ou deadlock). Le pire c'est que cela n'arrive pas souvent, mais quand cela
vous arrive c'est frustrant à déboguer.
|
 |
 |
 |
There is no language support to help
prevent deadlock; it’s up to you to avoid it by careful design. These are
not comforting words to the person who’s trying to debug a deadlocking
program.
|
 |
Il n'y a pas de support du langage pour aider à éviter les
interblocages; c'est à vous de les éviter en faisant attention à la
conception. Ce ne sont pas des mots pour rassurer la personne qui essaie de déboguer un
programme générant des inter-blocages.
|
 |
 |
 |
The deprecation of stop( ), suspend( ), resume( ), and
destroy( ) in Java
2
|
 |
La dépréciation de
stop(), suspend(), resume(), et destroy() en Java 2
|
 |
 |
 |
One change that has been made in Java 2
to reduce the possibility of deadlock is the deprecation of
Thread’s stop( ), suspend( ),
resume( ), and destroy( ) methods.
|
 |
Un changement qui a été fait dans Java 2 pour réduire
les possibilités d'inter-blocage est la dépréciation des méthodes de
Thread’ stop(), suspend(), resume(), et
destroy().
|
 |
 |
 |
The
reason that the stop( ) method is deprecated is because it
doesn’t release the locks that the thread has acquired, and if the objects
are in an inconsistent state (“damaged”) other threads can view and
modify them in that state. The resulting problems can be subtle and difficult to
detect. Instead of using stop( ), you should follow the example in
Blocking.java and use a flag to tell the thread when to terminate itself
by exiting its run( ) method.
|
 |
La méthode stop() est dépréciée parce
qu'elle ne libère pas les verrous que le thread a acquis, et si les objets sont dans un
état inconsistent (« damaged ») les autres threads peuvent les voir et
les modifiés dans cet état. Le problème résultant peut être
subtil et difficile à détecter. Plutôt que d'utiliser stop(), vous
devriez suivre l'exemple de Blocking.java et utiliser un drapeau pour dire au thread quand
se terminer en sortant de sa méthode run().
|
 |
 |
 |
There are times when a thread
blocks—such as when it is waiting for input—and it cannot poll a
flag as it does in Blocking.java. In these cases, you still
shouldn’t use stop( ), but instead you can use the
interrupt( ) method
in Thread to break out of the blocked
code:
|
 |
Il existe des situations où un thread se
bloque — comme quand il attend une entrée — mais il ne peut
pas positionner un drapeau comme il le fait dans Blocking.java. Dans ces cas, vous ne
devriez pas utiliser stop(), mais plutôt la méthode interrupt() de
Thread pour écrire le code bloquant:
|
 |
 |
 |
//: c14:Interrupt.java
// The alternative approach to using
// stop() when a thread is blocked.
// <applet code=Interrupt width=200 height=100>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
class Blocked extends Thread {
public synchronized void run() {
try {
wait(); // Blocks
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
System.out.println("Exiting run()");
}
}
public class Interrupt extends JApplet {
private JButton
interrupt = new JButton("Interrupt");
private Blocked blocked = new Blocked();
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(interrupt);
interrupt.addActionListener(
new ActionListener() {
public
void actionPerformed(ActionEvent e) {
System.out.println("Button pressed");
if(blocked == null) return;
Thread remove = blocked;
blocked = null; // to release it
remove.interrupt();
}
});
blocked.start();
}
public static void main(String[] args) {
Console.run(new Interrupt(), 200, 100);
}
} ///:~
|
 |
//: c14:Interrupt.java // L'approche alternative pour utiliser // stop() quand un thread est bloqué. // <applet code=Interrupt width=200 height=100> // </applet> import javax.swing.*; import java.awt.*; import java.awt.event.*; import com.bruceeckel.swing.*;
class Blocked extends Thread { public synchronized void run() { try { wait(); // Bloque } catch(InterruptedException e) { System.err.println("Interrupted"); } System.out.println("Exiting run()"); } }
public class Interrupt extends JApplet { private JButton interrupt = new JButton("Interrupt"); private Blocked blocked = new Blocked(); public void init() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(interrupt); interrupt.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Button pressed"); if(blocked == null) color="#0000ff">return; Thread remove = blocked; blocked = null; // pour le libérer remove.interrupt(); } }); blocked.start(); } public static void main(String[] args) { Console.run(new Interrupt(), 200, 100); } } ///:~
|
 |
 |
 |
The wait( ) inside
Blocked.run( ) produces the blocked thread. When you press the
button, the blocked reference is set to null so the garbage
collector will clean it up, and then the object’s interrupt( )
method is called. The first time you press the button you’ll see that the
thread quits, but after that there’s no thread to kill so you just see
that the button has been pressed.
|
 |
Le wait() dans Blocked.run() produit le thread bloqué.
Quand vous pressez le bouton, la référence blocked est placée à
null donc le garbage collector le nettoiera, la méthode interrupt() de l'objet
est alors appelée. La première fois que vous pressez le bouton vous verrez le thread
sortir, mais ensuite il n'y a plus de thread à tuer donc vous voyez juste que le bouton a
été pressé.
|
 |
 |
 |
The
suspend( ) and resume( ) methods turn out to be
inherently deadlock-prone. When you call suspend( ), the target
thread stops but it still holds any locks that it has acquired up to that point.
So no other thread can access the locked resources until the thread is resumed.
Any thread that wants to resume the target thread and also tries to use any of
the locked resources produces deadlock. You should not use
suspend( ) and resume( ), but instead put a flag in your
Thread class to indicate whether the thread should be active or
suspended. If the flag indicates that the thread is
suspended,
the thread goes into a wait using wait( ). When the flag indicates
that the thread should be resumed the thread is restarted with
notify( ). An example can be produced by modifying
Counter2.java. Although the effect is similar, you’ll notice that
the code organization is quite
different—anonymous
inner classes are used for all of the listeners and the Thread is an
inner class, which makes programming slightly more convenient since it
eliminates some of the extra bookkeeping necessary in
Counter2.java:
|
 |
Les méthodes suspend() et
resume() finissent par être sujettes aux inter-blocages. Quand vous appelez
suspend(), le thread cible s'arrête mais il conserve les verrous qu'il a acquis
à ce point. Ainsi aucuns autres threads ne peut accéder aux ressources
verrouillées jusqu'à ce que le thread soit redémarré. Un thread qui
veut redémarrer le thread cible et aussi essaye d'utiliser une des ressources
verrouillées produit un inter-blocage. Vous ne devriez pas utiliser suspend() et
resume(), mais plutôt mettre un drapeau dans votre classe Thread pour
indiqué si le thread devrait être actif ou suspendu. Si le drapeau indique que le
thread est suspendu, le thread rentre dans un wait(). Quand le drapeau indique que le thread
devrait être redémarré le thread est réactivé avec
notify(). Un exemple peut être produit en modifiant Counter2.java. Alors que
l'effet est similaire, vous remarquerez que l'organisation du code est assez
différente — des classes internes anonymes sont utilisées pour tous
les listeners et le Thread est une classe interne, ce qui rend la programmation
légèrement plus convenable puisqu'on élimine certaines complexités
nécessaires dans Counter2.java:
|
 |
 |
 |
//: c14:Suspend.java
// The alternative approach to using suspend()
// and resume(), which are deprecated in Java 2.
// <applet code=Suspend width=300 height=100>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
public class Suspend extends JApplet {
private JTextField t = new JTextField(10);
private JButton
suspend = new JButton("Suspend"),
resume = new JButton("Resume");
private Suspendable ss = new Suspendable();
class Suspendable extends Thread {
private int count = 0;
private boolean suspended = false;
public Suspendable() { start(); }
public void fauxSuspend() {
suspended = true;
}
public synchronized void fauxResume() {
suspended = false;
notify();
}
public void run() {
while (true) {
try {
sleep(100);
synchronized(this) {
while(suspended)
wait();
}
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
t.setText(Integer.toString(count++));
}
}
}
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(t);
suspend.addActionListener(
new ActionListener() {
public
void actionPerformed(ActionEvent e) {
ss.fauxSuspend();
}
});
cp.add(suspend);
resume.addActionListener(
new ActionListener() {
public
void actionPerformed(ActionEvent e) {
ss.fauxResume();
}
});
cp.add(resume);
}
public static void main(String[] args) {
Console.run(new Suspend(), 300, 100);
}
} ///:~
|
 |
//: c14:Suspend.java // L'approche alternative à l'utilisation de suspend() // et resume(), qui sont déprecié dans Java 2. // <applet code=Suspend width=300 height=100> // </applet> import javax.swing.*; import java.awt.*; import java.awt.event.*; import com.bruceeckel.swing.*;
public class Suspend extends JApplet { private JTextField t = new JTextField(10); private JButton suspend = new JButton("Suspend"), resume = new JButton("Resume"); private Suspendable ss = new Suspendable(); class Suspendable extends Thread { private int count = 0; private boolean suspended = color="#0000ff">false; public Suspendable() { start(); } public void fauxSuspend() { suspended = true; } public synchronized void fauxResume() { suspended = false; notify(); } public void run() { while (true) { try { sleep(100); synchronized(this) { while(suspended) wait(); } } catch(InterruptedException e) { System.err.println("Interrupted"); } t.setText(Integer.toString(count++)); } } } public void init() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(t); suspend.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { ss.fauxSuspend(); } }); cp.add(suspend); resume.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { ss.fauxResume(); } }); cp.add(resume); } public static void main(String[] args) { Console.run(new Suspend(), 300, 100); } } ///:~
|
 |
 |
 |
The flag suspended inside
Suspendable is used to turn suspension on and off. To suspend, the flag
is set to true by calling fauxSuspend( ) and this is detected
inside run( ). The wait( ), as described earlier in this
chapter, must be synchronized so that it has the object lock. In
fauxResume( ), the suspended flag is set to false and
notify( ) is called—since this wakes up wait( )
inside a synchronized clause the fauxResume( ) method must
also be synchronized so that it acquires the lock before calling
notify( ) (thus the lock is available for the wait( ) to
wake up with). If you follow the style shown in this program you can avoid using
suspend( ) and resume( ).
|
 |
Le drapeau suspended dans Suspendable est utilisé pour
activer ou désactiver la suspension. Pour suspendre, le drapeau est placé à
true en appelant fauxSuspend() et ceci est détecté dans run().
Le wait(), comme décrit plus haut dans ce chapitre, doit être
synchronized afin qu'il ait le verrou de l'objet. Dans fauxResume(), le drapeau
suspended est placé à false et notify() est
appelé — puisque ceci reveille wait() dans une clause
synchronized la méthode fauxResume() doit aussi être synchronized
afin qu'elle acquiert le verrou avant d'appeler notify() (ainsi le verrou est libre pour que
le wait() se réveille avec). Si vous suivez le style montré dans ce programme
vous pouvez éviter d'utiliser suspend() et resume().
|
 |
 |
 |
The
destroy( ) method of
Thread has never been implemented; it’s like a
suspend( ) that cannot resume, so it has the same deadlock issues as
suspend( ). However, this is not a deprecated method and it might be
implemented in a future version of Java (after 2) for special situations in
which the risk of a deadlock is acceptable.
|
 |
La méthode destroy() de Thread n'a jamais
été implémenter; c'est comme un suspend() qui ne peut pas être
réactivé, donc elle a les mêmes problèmes d'inter-blocage que
suspend(). Toutefois, ce n'est pas une méthode dépréciée et elle
devrait être implémentée dans une future version de Java (après la 2)
pour des situations spéciales où le risque d'inter-blocage est acceptable.
|
 |
 |
 |
You might wonder why these methods, now
deprecated, were included in Java in the first place. It seems an admission of a
rather significant mistake to simply remove them outright (and pokes yet another
hole in the arguments for Java’s exceptional design and infallibility
touted by Sun marketing people). The heartening part about the change is that it
clearly indicates that the technical people and not the marketing people are
running the show—they discovered a problem and they are fixing it. I find
this much more promising and hopeful than leaving the problem in because
“fixing it would admit an error.” It means that Java will continue
to improve, even if it means a little discomfort on the part of Java
programmers. I’d rather deal with the discomfort than watch the language
stagnate.
|
 |
Vous devez vous demander pourquoi ces méthodes, maintenant
dépréciées, étaient incluses dans Java dans un premier temps. Il
semblerait admissible qu'une erreur significative soit simplement supprimée (et donne encore
un autre coup aux arguments pour l'exceptionnel conception et l'infaillibilité
claironné par les commerciaux de Sun). La partie réconfortante à propos des
changements est que cela indique clairement que ce sont les techniciens et non les commerciaux qui
dirige le show — ils découvrent un problème et ils le fixent. Je
trouve cela beaucoup plus promettant et encourageant que de laisser le problème parce que
« fixer le problème serait admettre une erreur. » Cela signifie que
Java continuera à évoluer, même si cela signifie une petite perte de confort
pour les programmeurs Java. Je préfère accepter cet inconvénient plutôt
que de voir le langage stagné.
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |