Maison >Java >javaDidacticiel >Utilisation du mot-clé synchronisé
Le mot-clé synchronisé est un verrou de synchronisation couramment utilisé dans la programmation simultanée Java. Il est utilisé pour verrouiller des méthodes ou des blocs de code, il peut être synchronisé(this){}, synchronisé(Object){}. (classe) {}.
Le verrou sera automatiquement libéré lorsque le contenu verrouillé est exécuté ou qu'une exception est levée pendant l'exécution.
Si vous souhaitez libérer manuellement le verrou, vous devez appeler la méthode wait() de l'objet verrouillé pour libérer le verrou et le mettre dans un état d'attente, passer à d'autres threads à exécuter et la notification () réveille uniquement l'objet qui a été appelé. Méthode wait() d'autres threads, mais le verrou ne sera pas libéré et l'ordre de sélection n'est pas contrôlé par le code et est implémenté par la machine virtuelle.
Par conséquent, les méthodes wait(), notify() et notifyAll() de l'objet ne peuvent être utilisées qu'avec le mot-clé synchronisé pour terminer la planification entre les threads.
où la méthode verrouillée équivaut à synchronisé(this){tout le code de la méthode sous forme de bloc de code}, comme suit :
public synchronized void test() { ... }
est équivalent à
public void test() { synchronized (this) { ... } }
verrouillé dans l'exemple ci-dessus est un objet de cette classe. Si une méthode statique est verrouillée, on sait que la méthode statique appartient à la classe et non à l'objet. Par conséquent, la méthode statique modifiée par synchronisé verrouille tous les objets de cette classe, c'est à dire. Autrement dit, même deux objets Instance, tant qu'ils appartiennent à cette classe, seront verrouillés.
public synchronized static void test() { ... }
équivaut à
public static void test() { synchronized (所在类.class) { ... } }
Qu'il s'agisse d'une méthode de verrouillage ou d'un bloc de code, quel que soit l'objet de référence lors du verrouillage du bloc de code, c'est clair tant que vous vous en souvenez principe, c'est-à-dire lorsque les verrous de synchronisation de l'objet de référence ne fonctionnent que lorsqu'ils sont identiques, sinon les verrous ne s'excluent pas mutuellement et peuvent être exécutés simultanément.
synchronized(this) indique que le verrouillage prend effet lorsque les instances d'objet de la classe actuelle sont les mêmes, synchronisé(Object) indique que le verrouillage prend effet lorsque les objets Object sont les mêmes, et synchronisé(classe ) indique que le verrouillage prend effet lorsqu'ils sont tous de la même classe.
Donnez un exemple simple :
public class TestController { public class Task implements Runnable{ private String str; Task(String str){ this.str=str; } @Override public void run() { synchronized (str) { try { Thread.sleep(3000l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(str); } } } public static void main(String[] args) throws InterruptedException { TestController testController = new TestController(); Thread thread1 = new Thread(testController.new Task("1")); Thread thread2 = new Thread(testController.new Task("1")); thread1.start(); thread2.start(); } }
Dans le code ci-dessus, l'objet de référence str est entièrement "1". En Java, si la chaîne String passe this.str="1", Assignment. est équivalent à str=String.valueOf("1") Si la chaîne "1" a été initialisée auparavant, la précédente sera prise directement, c'est donc le même objet. Selon le principe introduit ci-dessus, le verrouillage prendra effet, le résultat est donc que 1 sera émis après 3 secondes et 1 sera émis après 3 secondes supplémentaires.
Si thread2 est remplacé par
Thread thread2 = new Thread(testController.new Task("2"));
alors l'un des objets de référence est "1" et l'autre est "2", qui ne sont pas le même objet, donc le verrou ne sera pas mutuellement exclusive fonctionne, donc le résultat est que 1 et 2 sont émis presque simultanément après 3 secondes.
Tous les éléments ci-dessus sont plusieurs threads appelant la même méthode en même temps. Que se passe-t-il si différentes méthodes sont appelées ?
public class Test{ public synchronized void m1(){ System.out.println("m1 running..."); try { Thread.sleep(3000l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("m1 end"); } public synchronized void m2(){ System.out.println("m2 running..."); System.out.println("m2 end"); } public static void main(String[] args) { Test test = new Test(); new Thread(new Runnable() { @Override public void run() { test.m1(); } }).start(); new Thread(new Runnable() { @Override public void run() { test.m2(); } }).start(); } }
Le résultat de sortie du code ci-dessus est :
m1 running... //过3秒 m1 end m2 running... m2 end
Comme mentionné ci-dessus, la modification synchronisée équivaut à synchronisé(this) {tout le code de la méthode sous forme de bloc de code}, et ceci représente est un objet, c'est-à-dire que le premier Thread obtient le verrou de l'objet de test Parce que les objets sont tous le même test, le deuxième Thread ne peut pas obtenir le verrou et est bloqué.
Changez l'exemple ci-dessus comme suit :
private String str = "1"; public void m1(){ synchronized(str){ System.out.println("m1 running..."); try { Thread.sleep(3000l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("m1 end"); } } public void m2(){ synchronized(str){ System.out.println("m2 running..."); System.out.println("m2 end"); } }
Lorsque le premier Thread appelle m1(), il obtient le verrou de l'objet str. Le deuxième Thread en a également besoin lorsqu'il appelle m2(. ). Obtenez le verrou de l'objet str, et comme ce sont le même objet Test, les deux str sont également le même objet, donc le deuxième Thread sera bloqué car il ne peut pas obtenir le verrou, et le résultat de sortie est le même que l'exemple précédent.
Si vous remplacez l'exemple ci-dessus par celui-ci :
public class M1 { public void m(String str){ synchronized (str) { System.out.println("m1 runing"); try { Thread.sleep(3000l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("m1 end"); } } } public class M2 { public void m(String str){ synchronized (str) { System.out.println("m2 runing"); System.out.println("m2 end"); } } } public class Test { public static void main(String[] args) { String str = "1"; new Thread(new Runnable() { @Override public void run() { new M1().m(str); } }).start(); new Thread(new Runnable() { @Override public void run() { new M2().m(str); } }).start(); } }
La méthode appelée cette fois est en deux classes, mais le résultat est le même que les deux exemples précédents, car les verrouillés Ils sont tous les objets str transmis. Il n'y a qu'un seul verrou pour le même objet Si le premier Thread le prend, le deuxième Thread ne peut qu'attendre.
Résumé :
A. Que le mot-clé synchronisé soit ajouté à une méthode ou à un objet, si l'objet sur lequel il agit est non statique, le verrou est activé. il acquiert est l'objet ; Si l'objet sur lequel la synchronisation agit est une méthode statique ou une classe, le verrou qu'il acquiert est pour la classe, et tous les objets de la classe ont le même verrou.
B. Chaque objet n'est associé qu'à un seul verrou. Celui qui obtient ce verrou peut exécuter le code qu'il contrôle.
C. La mise en œuvre de la synchronisation nécessite beaucoup de temps système et peut même provoquer un blocage, alors essayez d'éviter un contrôle de synchronisation inutile
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!