Cet article décrit la différence entre synchronisé (verrouillage d'objet) et synchronisé statique (verrouillage de classe) en Java. Partagez-le pour votre référence, comme suit:
La différence entre synchronisé et statique synchronisé
En analysant l'analyse de ces deux usages, nous pouvons comprendre le concept de verrouillage en Java. L'un est un verrouillage d'instance (verrouillé sur un objet d'instance. Si la classe est un singleton, alors le verrou a également le concept d'un verrou global), et l'autre est un verrou global (le verrou est ciblé sur une classe. Peu importe le nombre d'objets l'instance, les threads partagent le verrou). Le verrouillage d'instance correspond au mot clé synchronisé, tandis que le verrouillage de classe (verrouillage global) correspond au synchronisé statique (ou verrouillé sur l'objet de classe ou de chargeur de classe de la classe).
L'article suivant donne un bon résumé:
1. La différence entre synchronisé et statique synchronisé
Synchronisé verrouille l'instance actuelle (objet actuel) de la classe pour empêcher d'autres threads d'accéder à tous les blocs synchronisés de l'instance de la classe en même temps. Notez qu'il s'agit de "l'instance actuelle de la classe". Il n'y a pas une telle contrainte sur deux instances différentes de la classe.
Ensuite, STATIC Synchronisé contrôle l'accès simultané à toutes les instances de la classe, et STATIC Synchronisé restreint toutes les instances de la classe en multi-threads pour accéder au bloc de code correspondant à la classe en JVM en même temps. En fait, s'il est synchronisé dans une méthode ou un bloc de code dans une classe, après avoir généré une instance de la classe, l'instance aura également un bloc de surveillance pour empêcher les threads d'accéder simultanément au bloc de protection synchronisé de l'instance. Synchronisé statique est un bloc de surveillance commun à toutes les instances de la classe. C'est la différence entre les deux. En d'autres termes, la synchronisée est équivalente à cela. (Adressé plus tard)
Un auteur japonais, "Java Multithread Design Pattern" de Jie Chenghao a une chronique comme celle-ci:
Classe pulbic quelque chose () {public synchronisé void issynca () {} public synchronisé void issyncb () {} public statique synchronisé void cSynca () {} public statique synchronisé void cSyncb () {}}Donc, s'il y a deux instances x et y de quelque chose de classe, quel est le cas lorsque le groupe de méthodes suivant est accessible simultanément par plusieurs threads?
axissynca () et x.issyncb ()
bxissynca () et y.issynca ()
cxcSynca () et y.csyncb ()
dxissynca () et quelque chose.csynca ()
Ici, il est clair qu'il peut être jugé:
A, sont tous des accès de domaine synchronisés à la même instance (x) et ne peuvent donc pas être accessibles simultanément. (Différents domaines synchronisés qui accèdent X en multithreads ne peuvent pas être accessibles simultanément)
Si x.issynca () est accessible dans plusieurs threads, car il est toujours la même instance et verrouillé sur la même méthode, il ne peut pas être accessible dans plusieurs threads en même temps. (Le même domaine synchronisé qui accède X en multithreads ne peut pas être accessible en même temps)
B, est pour différentes instances, donc il est accessible en même temps (les verrous d'objet n'ont pas de contraintes de verrouillage pour différentes instances d'objet)
C, parce qu'il est synchronisé statique, différentes instances seront toujours restreintes, ce qui équivaut à quelque chose.issynca () et quelque chose.issyncb (), il ne peut donc pas être accessible en même temps.
Alors, qu'en est-il de D ?, La réponse dans le livre est accessible simultanément. La raison de la réponse est que synchronzed est que la méthode d'instance et la méthode de classe synchronzée sont différentes du verrou.
L'analyse personnelle signifie que synchronisé et statique synchronisé équivaut à deux gangs, chacun ayant son propre contrôle, et il n'y a aucune contrainte les uns sur les autres et est accessible en même temps.
Par exemple:
classe publique TestSynchronized {public synchronisé void test1 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); essayez {thread.sleep (500); } catch (InterruptedException ie) {}}} public static synchronisé void test2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); essayez {thread.sleep (500); } catch (InterruptedException ie) {}}} public static void main (String [] args) {final testSynchronisé myt2 = new TestSynchronized (); Thread test1 = new thread (new Runnable () {public void run () {myt2.test1 ();}}, "test1"); Thread test2 = new thread (new Runnable () {public void run () {testSynchronized.test2 ();}}, "test2"); test1.start (); test2.start (); // TestRunnable Tr = new TestRunnable (); // thread test3 = nouveau thread (tr); // test3.start (); }}test1: 4 test2: 4 test1: 3 test2: 3 test2: 2 test1: 2 test2: 1 test1: 1 test1: 0 test2: 0
Le code ci-dessus synchronisé modifie la méthode statique et la méthode d'instance en même temps, mais les résultats en cours d'exécution sont alternativement effectués, ce qui prouve que les verrous de classe et les verrous d'objets sont deux serrures différentes, contrôlant différentes régions, et elles n'interfèrent pas entre elles. De même, alors que les threads obtiennent des verrous d'objets, ils peuvent également obtenir ce type de verrouillage, c'est-à-dire qu'ils obtiennent deux verrous en même temps, ce qui est autorisé.
en conclusion:
R: La statique synchronisée est la portée d'une certaine classe. CSYNC statique synchronisé {} empêche plusieurs instances dans plusieurs threads d'accéder à la méthode statique synchronisée de cette classe en même temps. Il fonctionne sur toutes les instances d'objet d'une classe.
B: Synchronisé est la portée d'une instance. synchronisé issync () {} empêche cette instance d'accéder à la méthode synchronisée de cette classe en même temps.
En fait, il est très simple de résumer.
2. La différence entre la méthode synchronisée et le code synchronisé rapidement
Il n'y a pas de différence entre les méthodes synchronisées () {} et synchronisée (this) {}, mais les méthodes synchronisées () {} sont commode pour la compréhension de la lecture, tandis que synchronisée (this) {} peut contrôler plus précisément les conflits restreignent les zones d'accès, et parfois effectuer plus efficacement.
Comparaison de l'efficacité entre deux méthodes:
1. Synchronisez le bloc, le code est le suivant:
Importer java.util.concurrent.CountDownLatch; Importer java.util.concurrent.executorService; Importer java.util.concurrent.executors; classe publique TestSynchronized {/ ** * @param args * / public static void main (String [] args) {ExecutorService Service = exécutors.newcachedThreadpool (); COUNTDOWNLATCH COUNTAL FINAL CDORDR = NOUVEAU COUNTDOWNLATCH (1); CountdownLatch final cdanswer = nouveau compte à rebours (3); Final SynConizedClass sc = new SynConizedClass (); for (int i = 0; i <3; i ++) {runnable runnable = new Runnable () {public void run () {try {cdorder.Await (); sc.start (); cdanswer.CountDown (); } catch (exception e) {e.printStackTrace (); }}}; Service.Execute (Runnable); } essayez {thread.sleep ((long) (math.random () * 10000)); System.out.println ("thread" + thread.currentThread (). GetName () + "Publish Execution Commande"); CDORD.CountDown (); Long Begintime = System.Currenttimemillis (); System.out.println ("thread" + thread.currentThread (). GetName () + "La commande a été envoyée, en attendant le résultat"); cdanswer.Await (); System.out.println ("thread" + thread.currentThread (). GetName ()) + "Tous les résultats de la réponse ont été reçus, le temps pris est:" + (System.Currenttimemillis () - Begintime)); } catch (exception e) {e.printStackTrace (); } service.shutdown (); }} class SynConizedClass {public void start () lève InterruptedException {Thread.Sleep (100); // Exécuter une autre logique pour consommer le temps synchronisé (this) {System.out.println ("Je l'ai exécuté avec 10 ms"); }}} Les résultats de l'opération sont les suivants:
Le thread Main libère la commande d'exécution, le thread Main a envoyé la commande, en attendant le résultat que j'ai exécuté et utilisé 10 ms
J'ai coulé en utilisant 10 ms
J'ai coulé en utilisant 10 ms
Le thread Main a reçu tous les résultats de la réponse, et le temps pris est: 110
La méthode de synchronisation, le code est le suivant:
Importer java.util.concurrent.CountDownLatch; Importer java.util.concurrent.executorService; Importer java.util.concurrent.executors; classe publique TestSynchronized {/ ** * @param args * / public static void main (String [] args) {ExecutorService Service = exécutors.newcachedThreadpool (); COUNTDOWNLATCH COUNTAL FINAL CDORDR = NOUVEAU COUNTDOWNLATCH (1); CountdownLatch final cdanswer = nouveau compte à rebours (3); Final SynConizedClass sc = new SynConizedClass (); for (int i = 0; i <3; i ++) {runnable runnable = new Runnable () {public void run () {try {cdorder.Await (); sc.start (); cdanswer.CountDown (); } catch (exception e) {e.printStackTrace (); }}}; Service.Execute (Runnable); } essayez {thread.sleep ((long) (math.random () * 10000)); System.out.println ("thread" + thread.currentThread (). GetName () + "Publish Execution Commande"); CDORD.CountDown (); Long Begintime = System.Currenttimemillis (); System.out.println ("thread" + thread.currentThread (). GetName () + "La commande a été envoyée, en attendant le résultat"); cdanswer.Await (); System.out.println ("thread" + thread.currentThread (). GetName ()) + "Tous les résultats de la réponse ont été reçus, le temps pris est:" + (System.Currenttimemillis () - Begintime)); } catch (exception e) {e.printStackTrace (); } service.shutdown (); }} class SynConizedClass {public synchronisé void start () lance InterruptedException {Thread.Sleep (100); // Exécuter un autre temps logique // synchronisé (this) {System.out.println ("J'ai utilisé 10 ms"); //}}}Les résultats de l'opération sont les suivants:
Le thread Main libère la commande d'exécution, le thread Main a envoyé la commande, en attendant le résultat que j'ai exécuté et utilisé 10 ms
J'ai coulé en utilisant 10 ms
J'ai coulé en utilisant 10 ms
Le thread Main a reçu tous les résultats de la réponse, et le temps pris est: 332
La différence entre les deux est: 222 ms.
La comparaison montre que les blocs de code synchrones sont plus efficaces que les méthodes de synchronisation.
Mémoire supplémentaire:
1. Il existe deux portées de mots clés synchronisés:
1) Il se situe dans une instance d'objet. Amethod () synchronisé {} peut empêcher plusieurs threads d'accéder à la méthode synchronisée de cet objet en même temps (si un objet a plusieurs méthodes synchronisées, tant qu'un thread accède à l'une des méthodes synchronisées, d'autres threads ne peuvent accéder à aucune méthode synchronisée dans l'objet en même temps). À l'heure actuelle, la méthode synchronisée de différentes instances d'objet est ininterrompue. C'est-à-dire que d'autres threads peuvent toujours accéder à la méthode synchronisée dans une autre instance d'objet de la même classe en même temps;
2) C'est la portée d'une certaine classe. ASTATICMetHod statique synchronisé {} empêche différents objets d'instance (ou le même objet d'instance) dans plusieurs threads d'accéder à la méthode statique synchronisée dans cette classe en même temps. Il fonctionne sur toutes les instances d'objet d'une classe.
2. En plus d'utiliser le mot-clé synchronisé avant la méthode, le mot-clé synchronisé peut également être utilisé dans un bloc dans la méthode, indiquant qu'un accès mutuellement exclusif est effectué sur les ressources de ce bloc. L'utilisation est: synchronisée (this) {/ * block * /} (ou synchronisé (obj) {/ * bloc * /}), et son étendue est l'objet actuel;
3. Le mot-clé synchronisé ne peut pas être hérité. C'est-à-dire que la méthode de la classe de base synchronisée f () {} n'est pas automatiquement synchronisée f () {} dans la classe héréditaire, mais devient f () {}. La classe d'héritage vous oblige à spécifier explicitement que l'une de ses méthodes est synchronisée;
Une certaine compréhension de la synchronisation (ceci) (expliquez bien le verrouillage de l'objet, faites attention à ce mot clé)
1. Lorsque deux threads simultanés accèdent à ce bloc de code synchronisé synchronisé (ce) dans le même objet d'objet, un seul thread peut être exécuté dans un temps. Un autre thread doit attendre que le thread actuel exécute ce bloc de code avant de pouvoir exécuter le bloc de code.
2. Cependant, lorsqu'un thread accède à un bloc de code de synchronisation synchronisé (this) d'un objet, un autre thread peut toujours accéder au bloc de code de synchronisation non synchronisé (this) dans cet objet.
3. Il est particulièrement essentiel que lorsqu'un thread accède à un bloc de code de synchronisation synchronisé (cette) de synchronisation d'un objet, d'autres threads bloqueront l'accès à tous les autres blocs de code de synchronisation synchronisés (this) dans l'objet.
4. Le troisième exemple s'applique également à d'autres blocs de code synchrones. Autrement dit, lorsqu'un thread accède à un bloc de code de synchronisation synchronisé (ce) synchronisation d'un objet, il obtient le verrouillage de l'objet de cet objet. En conséquence, d'autres threads accès à toutes les parties de code synchrones de l'objet objet sont temporairement bloqués.
5. Les règles ci-dessus s'appliquent également aux autres verrous d'objets.
Ajoutez un morceau de code pour faciliter le test des mots clés synchronisés (modification simple)
classe publique TestSynchronized {public void test1 () {synchronisé (this) {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); essayez {thread.sleep (500); } catch (InterruptedException ie) {}}}} public synchronisé void test2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); essayez {thread.sleep (500); } catch (InterruptedException ie) {}}} public synchronisé void test3 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); essayez {thread.sleep (500); } catch (InterruptedException ie) {}}} public static void main (String [] args) {final testSynchronisé myt2 = new TestSynchronized (); TestSynchronisé final MYT3 = nouveau TestSynchronized (); Thread test1 = new thread (new Runnable () {public void run () {myt2.test2 ();}}, "test1"); Thread test2 = new thread (new Runnable () {public void run () {myt2.test3 ();}}, "test3"); test1.start () ;; test2.start (); }} Résultats en cours:
test1: 4test1: 3test1: 2test1: 1test1: 0test3: 4test3: 3test3: 2test3: 1test3: 0
Ci-dessous, nous nous concentrons sur l'utilisation de sychronisés dans Java, ce qui est spécifiquement: la méthode de synchronisation et le mot-clé synchronisé du bloc synchronisé, qui comprend deux usages: la méthode synchronisée et le bloc synchronisé.
1. Méthode synchronisée: Déclarez la méthode synchronisée en ajoutant le mot-clé synchronisé à la déclaration de la méthode. comme:
public synchronisé void AccessVal (int newval);
La méthode synchronisée contrôle l'accès aux variables des membres de la classe: chaque instance de classe correspond à un verrou et chaque méthode synchronisée doit obtenir le verrouillage de l'instance de classe qui appelle la méthode avant de pouvoir être exécutée. Sinon, le fil auquel il appartient est bloqué. Une fois la méthode exécutée, elle occupera exclusivement la serrure. Le verrou ne sera pas libéré avant son retour de la méthode. Le fil bloqué peut obtenir le verrou et rentrer à l'état exécutable. Ce mécanisme garantit qu'en même temps, pour chaque instance de classe, tout au plus une de toutes les fonctions membres déclarées synchronisées se trouve dans un état exécutable (car tout le plus peut obtenir le verrou correspondant à l'instance de classe), évitant ainsi efficacement les conflits d'accès des variables des membres de la classe (tant que toutes les méthodes possibles pour accéder aux variables des membres de la classe sont déclarées synchronisées).
Dans Java, non seulement les instances de classe, chaque classe correspond également à un verrou, nous pouvons donc déclarer la fonction membre statique de la classe comme statique synchronisée pour contrôler son accès aux variables membre statiques de la classe.
L'inconvénient de la méthode synchronisée: déclarer une grande méthode comme synchronisée affectera grandement l'efficacité. En règle générale, si la méthode de la classe de thread est exécutée () est déclarée synchronisée, car elle fonctionne tout au long de la vie du fil, elle ne réussira jamais à aucune méthode synchronisée de cette classe. Bien sûr, nous pouvons résoudre ce problème en mettant le code qui accède aux variables des membres de la classe dans une méthode spéciale, en la déclarant synchronisée et en l'appelant dans la méthode principale, mais Java nous fournit une meilleure solution, c'est-à-dire le bloc synchronisé.
2. Bloc synchronisé: Déclarez le bloc synchronisé via le mot-clé synchronisé. La syntaxe est la suivante:
synchronisé (syncobject) {// code qui permet le contrôle d'accès} Le bloc synchronisé est un bloc de code dans lequel le code doit obtenir un verrou du Syncobject d'objet (comme mentionné précédemment, il peut être une instance de classe ou une classe) avant de pouvoir être exécuté. Le mécanisme spécifique est le même que celui décrit ci-dessus. Puisqu'il peut être ciblé sur n'importe quel bloc de code et que les objets verrouillés peuvent être spécifiés à tout moment, il est plus flexible.
Avis:
Lorsque vous utilisez des mots clés synchronisés, vous devez éviter d'utiliser autant que possible des méthodes de sommeil ou de rendement dans des méthodes synchronisées ou des blocs synchronisés, car les blocs de programme synchronisés occupent les verrous d'objets, donc si vous vous reposez, d'autres threads ne peuvent être exécutés qu'en attendant que vous vous réveilliez et terminez l'exécution. Non seulement il affecte sérieusement l'efficacité, mais il n'est pas non plus logique.
De même, il n'a pas de sens d'appeler la méthode Yeild dans le bloc de programme synchrone pour abandonner la ressource CPU, car vous occupez le verrou et d'autres threads mutex ne peuvent toujours pas accéder au bloc de programme synchrone. Bien sûr, les threads qui ne sont pas liés aux blocs de programme synchrones peuvent obtenir plus de temps d'exécution.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.