Si un thread T1 entre dans une méthode m1 en obtenant le verrou de niveau classe, cela signifie-t-il qu'un autre thread T2 ne peut pas exécuter une méthode différente m2 en obtenant le verrou de niveau objet?
Non, ça ne veut pas dire ça. Le "verrou de niveau de classe" est juste un verrou normal sur un objet différent, à savoir SomeClass.class
. Le "verrouillage de niveau d'objet" se verrouille sur this
.
Edit: Juste pour m'assurer que je comprends bien la terminologie, vous vous demandez si m1 et m2 peuvent être utilisés simultanément comme ils sont définis ci-dessous:
public class SomeClass {
public synchronized static void m1() {
//do something
}
public synchronized void m2() {
//do something
}
}
Et la réponse est oui, m1 et m2 peuvent être exécutés simultanément. Il est fonctionnellement équivalent à ceci:
public class SomeClass {
public static void m1() {
synchronized (SomeClass.class) {
//do something
}
}
public void m2() {
synchronized (this) {
//do something
}
}
}
Puisqu'ils se synchronisent sur des objets complètement différents, ils ne s'excluent pas mutuellement.
Le verrouillage au niveau de l'objet est un mécanisme lorsque vous souhaitez synchroniser une méthode non statique ou un bloc de code non statique, de sorte qu'un seul thread puisse exécuter le bloc de code sur une instance donnée de la classe. Cela devrait toujours être fait pour sécuriser le thread de données au niveau instance. Cela peut être fait comme ci-dessous:
public class DemoClass
{
public synchronized void demoMethod(){}
}
or
public class DemoClass
{
public void demoMethod(){
synchronized (this)
{
//other thread safe code
}
}
}
or
public class DemoClass
{
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
Le verrouillage au niveau classe empêche plusieurs threads d'entrer dans un bloc synchronisé dans toutes les instances disponibles au moment de l'exécution. Cela signifie que s'il y a 100 instances de DemoClass au moment de l'exécution, un seul thread pourra exécuter demoMethod () dans toutes les instances à la fois, et toutes les autres instances seront verrouillées pour les autres threads. Cela devrait toujours être fait pour sécuriser les threads de données statiques.
public class DemoClass
{
public synchronized static void demoMethod(){}
}
or
public class DemoClass
{
public void demoMethod(){
synchronized (DemoClass.class)
{
//other thread safe code
}
}
}
or
public class DemoClass
{
private final static Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
}
En Java, il existe deux types de verrous:
Dans le cas de méthodes statiques, le verrou est toujours vérifié sur la classe , Mais dans le cas de méthodes exemple, le verrou est toujours vérifié sur objet.
Exemple:
show1()
est non statique et show()
est static . Maintenant, show()
est appelé par nom de classe (ou par objet) et show1()
est appelé par objet , les deux méthodes peuvent alors accéder à simultanément par deux threads.
class Shared{
static int x;
static synchronized void show(String s,int a){
x=a;
System.out.println("Starting in method "+s+" "+x);
try{
Thread.sleep(2000);
}
catch(Exception e){ }
System.out.println("Ending from method "+s+" "+x);
}
synchronized void show1(String s,int a){
x=a;
System.out.println("Starting show1 "+s);
try{
Thread.sleep(2000);
}
catch(Exception e){ }
System.out.println("Ending from show1 "+s);
}
}
class CustomThread extends Thread{
Shared s;
public CustomThread(Shared s,String str){
super(str);
this.s=s;
start();
}
public void run(){
Shared.show(Thread.currentThread().getName(),10);
}
}
class CustomThread1 extends Thread{
Shared s;
public CustomThread1(Shared s,String str){
super(str);
this.s=s;
start();
}
public void run(){
s.show1(Thread.currentThread().getName(),20);
}
}
public class RunSync {
public static void main(String[] args) {
Shared sh=new Shared();
CustomThread t1=new CustomThread(sh,"one");
CustomThread1 t2=new CustomThread1(sh,"two");
}
}
Sortie:
Starting in method one 10
Starting show1 two
Ending from method one 20
Ending from show1 two
Exemple pour comprendre les verrous au niveau des objets et des classes en Java
1) Exemple de verrouillage du niveau d'objet
package com.test;
public class Foo implements Runnable {
@Override
public void run() {
Lock();
}
public void Lock() {
System.out.println(Thread.currentThread().getName());
synchronized(this) {
System.out.println("in block " + Thread.currentThread().getName());
System.out.println("in block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Foo b1 = new Foo();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Foo b2 = new Foo();
Thread t3 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
sortie:
t1
t3
t2
in block t3
in block t1
in block t3 end
in block t1 end
in block t2
Notez que t3 ne bloquera pas lorsque les threads t1 et t2 se bloqueront. Parce que le verrou est placé sur cet objet et que le thread t3 diffère de cet objet que le thread t1, t2
2) Exemple de verrouillage de niveau de classe
Le code dans le verrouillage de niveau objet, seul Foo.class est ajouté dans un bloc synchronisé. Tous les threads en cours de création à l'aide d'un objet de la classe Foo seront bloqués.
package com.test;
public class Foo implements Runnable {
@Override
public void run() {
Lock();
}
public void Lock() {
System.out.println(Thread.currentThread().getName());
synchronized(Foo.class) {
System.out.println("in block " + Thread.currentThread().getName());
System.out.println("in block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Foo b1 = new Foo();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Foo b2 = new Foo();
Thread t3 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
sortie:
t1
t3
in block t1
in block t1 end
t2
in block t3
in block t3 end
in block t2
in block t2 end
Le bloc synchronisé va être exécuté pour le même thread.
Le verrouillage de niveau de classe est obtenu à l'aide du mot clé "Synchronisé statique, où le niveau d'objet est uniquement atteint par le mot clé synchronized. Le verrouillage de niveau d'objet permet de limiter le fonctionnement d'un même objet via un autre thread, tandis qu'un verrouillage de niveau de classe est obtenu. restreindre tout objet à fonctionner.
Si un thread T1 entre dans une méthode m1 en obtenant le verrou de niveau classe, cela signifie-t-il qu'un autre thread T2 ne peut pas exécuter une méthode différente m2 en obtenant le verrou de niveau objet?
Les verrous de niveau objet et de classe sont différents. Dans le cas ci-dessus, T2 peut exécuter la méthode m2 en obtenant le verrouillage au niveau de l'objet. Mais si m2 est static synchronized
, T2 ne peut pas appeler la méthode m2 à moins que T1 ne libère le verrouillage de classe sur la méthode m1.
Il n'est pas possible que deux invocations de méthodes synchronized
sur le même objet s'entrelacent. Lorsqu'un thread exécute une méthode synchronized
pour un objet, tous les autres threads qui invoquent des méthodes synchronized
pour le même bloc d'objet (suspendre l'exécution) jusqu'à ce que le premier thread soit terminé avec l'objet.
Supposons que vous ayez deux méthodes synchronized
m1 et m2 sur l'objet O. Si le thread T1 est en cours d'exécution de la méthode m1, alors le thread T2 doit attendre pour appeler la méthode m2 sur le même objet O, sauf si le verrou de libération du thread T1 sur la méthode m1.
Thread acquiert le verrou intrinsèque pour l'objet Class
associé à la classe. Ainsi, l'accès aux champs static
de la classe est contrôlé par un verrou distinct de celui de toute instance de la classe.
Supposons que la méthode m1 est static synchrnozed
et que la méthode m2 soit aussi static synchronized
et que vous avez deux objets différents, o1 et o2.
Si le thread T1 est en cours d'exécution de la méthode m1 sur l'objet o1, le thread T2 doit attendre pour appeler la méthode m2 sur l'objet o2 à moins que Thread T1 ne verrouille la méthode m1.
Différentes façons de verrouiller le niveau de classe: 1) Public class DemoClass {
public static synchronized void demoMethod(){
//dosomething
}
}
2)
classe publique DemoClass {
public void demoMethod(){
synchronized(DemoClass.class){
//dosomething
}
}
}
3)
classe publique DemoClass {
private final static Object lock = new Object();
public void demoMethod(){
synchronized(lock){
//dosomething
}
}
}
Il est possible que les méthodes synchronisées statiques et synchronisées non statiques puissent être exécutées simultanément ou simultanément car elles se verrouillent sur un objet différent.
Les verrous de niveau classe et instance sont différents. Les deux ne se gênent pas. Si une instance d’une classe a déjà été verrouillée par un thread, elle ne peut pas être verrouillée par un autre thread tant que ce verrou n’est pas libéré par le premier thread. Le même comportement existe pour le verrouillage au niveau de la classe.
Mais si un thread acquiert un verrou de niveau Classe, un autre thread peut acquérir un verrou sur l'une de ses instances. Les deux peuvent travailler en parallèle.
package lock;
class LockA implements Runnable {
@Override
public void run() {
synchronized (LockA.class) {
System.out.println("Class");
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestClassVsInstanceLock {
public static void main(String[] args) {
final LockA a = new LockA();
final LockA b = new LockA();
try {
Thread t = new Thread(a);
Thread t1 = new Thread() {
@Override
public void run() {
synchronized (b) {
System.out.println("Instance 1"+ currentThread().currentThread().holdsLock(b));
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
t1.start();
synchronized (a) {
System.out.println("Instance2");
Thread.sleep(10 * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
`
Cela affichera: - Instance2 Classe Instance 1true
Tous seront imprimés instantanément sans aucune pause.