Je suis nouveau à multithreading, et j'ai écrit ce code qui imprime les chiffres 1-10000 en exécutant simultanément des threads incrémentez et imprimez une variable.
Voici le code que j'utilise: P>
package threadtest; public class Main{ static int i=0; static Object lock=new Object(); private static class Incrementer extends Thread{ @Override public void run(){ while (true){ synchronized(lock){ if (i>=10000) break; i++; System.out.println(i); } } } } public static void main(String[] args) { new Incrementer().start(); new Incrementer().start(); new Incrementer().start(); new Incrementer().start(); new Incrementer().start(); new Incrementer().start(); } }
5 Réponses :
où il existe un "sucre syntaxique" d'une sorte de serrures dans Java est que alors pourquoi voudriez-vous faire la deuxième version au lieu du premier? P> synchronisé code> n'est en aucun cas du sucre syntaxique pour quoi que ce soit. Il n'y a aucun moyen de travailler en java sans utiliser le mot-clé code> synchronisé code>.
synchronisé code> peut Appliquez à la fois aux blocs (comme vous l'avez fait ci-dessus) et à des méthodes entières. Les deux méthodes suivantes sont à peu près équivalentes en sémantique: p>
code> pour le verrouillage qui vous donne une sémantique de verrouillage plus flexible. LI>
ul> p>
Avec un bloc, vous pouvez utiliser un objet privé comme verrou, ce qui empêche les interférences du code externe.
Depuis Java 1.5, vous pouvez java.util.concurrent.lock pour protéger l'accès aux régions critiques. Ceci est en fait plus rapide que d'utiliser synchronisé dans 1,5 et 1,6. Donc, votre déclaration liminaire est fausse.
On dirait que vos sources ne sont pas fausses. Le mot clé Pour plus d'informations sur la synchronisation en Java: P>
Syncrhonized code> est important à utiliser - et à utiliser correctement - lors de l'écriture du code de la sécurité thread-Safe. Et cela ressemble à vos propres expériences en supporter cela. P>
La synchronisation est l'un des concepts les plus importants lors de la programmation dans l'environnement multi-thread.
Lors de l'utilisation de la synchronisation, il faut envisager l'objet sur lequel la synchronisation a lieu.
Par exemple, si une méthode statique doit être synchronisée, la synchronisation doit être sur le niveau de la classe à l'aide de si la méthode du bloc d'instance doit être synchronisée, la synchronisation doit utiliser une instance de un objet qui est partagé entre tous les fils.
La plupart des gens vont mal avec le deuxième point tel qu'il apparaît dans votre code où la synchronisation semble être sur différents objets plutôt qu'un seul objet. P> P>
En fait, comme de Java 5, vous avez un ensemble alternatif d'outils dans Java.Util.ConCurrent. Voir ici pour plus de détails. Comme indiqué dans l'article, le modèle de verrouillage du moniteur fourni au niveau linguistique de Java présente un certain nombre de limitations significatives et peut être difficile à raisonner lorsqu'il existe un ensemble complexe d'objets interdépendants et des relations de verrouillage interdépendantes rend une possibilité réelle en direct. La bibliothèque Java.Util.ConCurrent propose une sémantique de verrouillage qui pourrait être plus familière aux programmeurs qui ont eu de l'expérience dans des systèmes de type POSIX P>
Bien sûr, "synchronisé" est juste du sucre syntaxique - Sucre syntaxique utile extrêmement utile. P>
Si vous voulez des programmes Java sans sucre, vous devriez écrire directement dans le code d'octet Java, le Monitorenter em>, monitorexit em>, verrouillage em>, et déverrouiller les opérations em> référencées dans Spécifications VM 8.13 Serrures et synchronisation P>
Il y a un verrou associé à chaque objet. La programmation Java
la langue ne fournit pas de moyen de
effectuer une serrure séparée et déverrouiller
opérations; Au lieu de cela, ils sont
implicitement effectué par de haut niveau
constructions qui arrangent toujours pour paire
ces opérations correctement. (Le java
machine virtuelle, cependant, fournit
Moniteur séparé et monatorexit
instructions qui implémentent la serrure
et déverrouillez les opérations.) p>
L'instruction synchronisée calcule un
référence à un objet; alors
tente d'effectuer une opération de verrouillage
sur cet objet et ne procède pas
plus loin jusqu'à ce que l'opération de verrouillage ait
complété avec succès. (Un verrou
opération peut être retardée parce que le
Les règles concernant les verrous peuvent empêcher le principal
mémoire de participer jusqu'à certains
autre thread est prêt à effectuer un
ou plus de déverrouillage des opérations.) Après le
le verrouillage a été effectué, le
Le corps de l'instruction synchronisée est
réalisé. Normalement, un compilateur pour le
Le langage de programmation Java garantit que
l'opération de verrouillage mise en œuvre par un
Instruction Monitorenter exécutée
avant l'exécution du corps de
L'instruction synchronisée est assortie
par une opération de déverrouillage mise en œuvre par
une instruction de monatorexit chaque fois que le
déclaration synchronisée complète,
Si l'achèvement est normal ou
brusque. p>
une méthode synchronisée automatiquement
effectue une opération de verrouillage quand il est
invoqué; son corps n'est pas exécuté
jusqu'à ce que l'opération de verrouillage ait
complété avec succès. Si la méthode
est une méthode d'instance, il verrouille le
verrouillage associé à l'instance pour
qu'il a été invoqué (c'est-à-dire le
objet qui sera connu comme ça
Au cours de l'exécution de la méthode
corps). Si la méthode est statique, elle
verrouille le verrou associé à la
Objet de classe qui représente la classe
dans lequel la méthode est définie. Si
L'exécution du corps de la méthode est toujours
terminé, normalement ou
brusquement, une opération de déverrouillage est
effectué automatiquement sur cette même
Verrouiller. P>
la meilleure pratique est que si une variable est
jamais à être attribué par un fil et
utilisé ou attribué par un autre, alors tous
accès à cette variable devrait être
enfermé dans des méthodes synchronisées ou
déclarations synchronisées. P>
Bien qu'un compilateur pour le Java
Langage de programmation normalement
Garanties Utilisation structurée des serrures
(Voir la section 7.14, "Synchronisation"),
rien ne garantit que tous les codes
Soumis à la machine virtuelle Java
obéira à cette propriété.
Mises en œuvre de la virtuelle Java
la machine sont autorisées mais non requises
appliquer les deux des deux suivants
Règles garantissant le verrouillage structuré. P>
Soit être un fil et l être une serrure.
Alors: p>
Nombre d'opérations de verrouillage effectuées par T sur L pendant une méthode
L'invocation doit être égale au nombre de
Déverrouiller les opérations effectuées par T sur l
Au cours de l'invocation de la méthode si
L'invocation de la méthode complète
normalement ou brusquement. p> li>
à aucun point au cours d'une invocation de méthode ne peut le nombre de déverrouillage
Opérations effectuées par T sur L depuis
L'invocation de la méthode dépasse la
Nombre d'opérations de verrouillage effectuées par
T sur l depuis l'invocation de la méthode. p> li>
ol>
en termes moins formels, lors d'une méthode
Invocation chaque opération de déverrouillage sur l
doit correspondre à un peu de verrouillage précédent
opération sur l. p>
Notez que le verrouillage et le déverrouillage
effectué automatiquement par le Java
machine virtuelle lorsque vous invoquez un
La méthode synchronisée est considérée comme
se produire pendant la méthode d'appel
Invocation. P>
blockQuote>
Ce n'est certainement pas. Pouvez-vous citer les sources où vous avez entendu cela?
@Balusc: voir la réponse acceptée. Je pense que les sources faisaient simplement référence à des méthodes synchronisées comme sucre syntaxique - je ne sais pas si c'est exactement correct ou non, mais au moins cela ne contredit pas mes conclusions comme je le pensais. @skaffman: J'aurais pu me tromper mal sans
synchronisé code> pour tout ce que je savais :)
@1crediiman
synchronisé code> sur une méthode est plus ou moins la même chose que la mise en place du corps de la méthode dans
synchronisé (this) {...} code> (ou pour une statique Méthode
synchronisé (myClass.class) {...} code>). (Il est représenté différemment dans les fichiers de classe, mais cela ne devrait généralement pas vous inquiéter.)
BTW: Comme vous êtes susceptible d'avoir biaisé verrouillé, (c'est la valeur par défaut) Un thread prendra la serrure et les autres vont dormir. C'est-à-dire qu'il est fort probable que tout le travail soit fait par un thread, les threads restants attendront qu'il finisse. Ce n'est pas un bogue et, dans votre cas, c'est le moyen le plus efficace d'exécuter ces threads.
@Peter: le travail n'est pas fait tout par un fil. Dans une variation du code ci-dessus, j'ai donné à chaque filetage un nom et les a envoyées de leurs noms avec les chiffres - les travaux ont été partagés de manière égale. Avez-vous une idée de savoir pourquoi cela se produirait?
Pourquoi ne pas simplement utiliser le mot-clé «CE» pour obtenir une serrure plutôt qu'un nouvel objet (inutile).
@1crediiman, utilisez-en-usermocking est désactivé par défaut sur Java 5.0, certaines versions de Java 6 Il est par défaut.
@Gnarly, à l'aide d'un objet de verrouillage empêche un appelant externe ou une sous-classe de verrouiller le même verrou. Cependant, dans ce cas, le verrouillage sur "Ceci" serait inutile de "ceci" est un objet différent dans chaque thread. Pour un contexte statique, vous avez besoin d'une classe comme "incrémenter.class"