6
votes

Est «synchronisé» vraiment juste du sucre syntaxique?

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();
    }
}


8 commentaires

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é pour tout ce que je savais :)


@1crediiman synchronisé 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) {...} (ou pour une statique Méthode synchronisé (myClass.class) {...} ). (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"


5 Réponses :


14
votes

synchronisé 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é synchronisé .

où il existe un "sucre syntaxique" d'une sorte de serrures dans Java est que synchronisé 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: xxx

alors pourquoi voudriez-vous faire la deuxième version au lieu du premier?

  • Les invocations de méthodes synchronisées sont beaucoup plus lentes que les invocations de méthodes anciennes simples, comme par un ordre de grandeur. Si votre code synchronisé n'est pas garanti de toujours exécuter (disons qu'il est sous un conditionnel), vous ne voulez probablement pas synchroniser toute la méthode.
  • Les procédés synchronisés contiennent des serrures plus longs que des blocs synchronisés (en raison de tout le code de configuration de la méthode / DÉPARTEMENT). La deuxième méthode ci-dessus conserve la serrure pendant moins de temps car le temps passé à installer et à déchirer le cadre de la pile ne sera pas verrouillé.
  • Vous pouvez avoir beaucoup de contrôle plus fin sur ce que vous verrouillez si vous allez avec les blocs synchronisés.
  • (courtoisie de Starblue ) Les blocs synchronisés peuvent utiliser des objets autres que pour le verrouillage qui vous donne une sémantique de verrouillage plus flexible.

2 commentaires

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.



1
votes

On dirait que vos sources ne sont pas fausses. Le mot clé Syncrhonized 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.

Pour plus d'informations sur la synchronisation en Java:

Méthodes synchronisées Java

Serrures Java et instructions synchronisées


0 commentaires

0
votes

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 xxx

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.


0 commentaires

1
votes

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


0 commentaires

1
votes

Bien sûr, "synchronisé" est juste du sucre syntaxique - Sucre syntaxique utile extrêmement utile.

Si vous voulez des programmes Java sans sucre, vous devriez écrire directement dans le code d'octet Java, le Monitorenter , monitorexit , verrouillage , et déverrouiller les opérations référencées dans Spécifications VM 8.13 Serrures et synchronisation

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.)

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.

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.

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.

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é.

Soit être un fil et l être une serrure. Alors:

  1. 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.

  2. à 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.

    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.

    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.


0 commentaires