Sobes.tech
Middle

Qu'est-ce que le bloc synchronized en Java et quels problèmes peuvent survenir lors de son utilisation?

sobes.tech IA

Réponse de l'IA

Le bloc synchronized en Java est utilisé pour assurer la synchronisation de l'accès à une ressource partagée entre plusieurs threads. Cela garantit qu'un seul thread peut exécuter le code à l'intérieur du bloc à tout moment.

Structure du bloc synchronized:

synchronized (objet_monitor) {
    // Section critique du code
    // Opérations sur la ressource partagée
}
  • objet_monitor : Tout objet qui sert de moniteur (lock). Les threads tentant d'entrer dans un bloc synchronized avec le même objet moniteur seront bloqués jusqu'à ce que le thread actuel sorte du bloc.

Problèmes pouvant survenir lors de l'utilisation de synchronized :

  • Interblocage (Deadlock) : Deux ou plusieurs threads attendent de libérer des ressources occupées par d'autres threads, ce qui entraîne un blocage de l'application. Cela peut se produire si les threads tentent d'obtenir des verroux dans des ordres différents.
  • Réduction des performances : La synchronisation bloque l'exécution d'autres threads en attente d'accéder au moniteur, ce qui peut ralentir les applications parallèles.
  • Inapplicabilité dans certains scénarios : Le bloc synchronized fournit un accès exclusif. Dans certains cas, une gestion plus flexible de l'accès peut être nécessaire (par exemple, lecture par plusieurs threads simultanément, écriture par un seul thread).
  • Complexité de débogage : Les problèmes de synchronisation peuvent être peu évidents et difficiles à reproduire et à déboguer.

Exemple d'interblocage :

class Resource {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1(Resource other) {
        synchronized (lock1) {
            try {
                Thread.sleep(100); // Simulation de travail
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " a acquis lock1");
            synchronized (other.lock2) {
                System.out.println(Thread.currentThread().getName() + " a acquis le lock2 de l'autre ressource");
            }
        }
    }

    public void method2(Resource other) {
        synchronized (lock2) {
             try {
                Thread.sleep(100); // Simulation de travail
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " a acquis lock2");
            synchronized (other.lock1) {
                System.out.println(Thread.currentThread().getName() + " a acquis le lock1 de l'autre ressource");
            }
        }
    }
}

public class DeadlockExample {
    public static void main(String[] args) {
        Resource r1 = new Resource();
        Resource r2 = new Resource();

        new Thread(() -> r1.method1(r2), "Thread-1").start();
        new Thread(() -> r2.method2(r1), "Thread-2").start();
    }
}

Dans cet exemple, Thread-1 tente d'obtenir lock1 sur r1 puis lock2 sur r2. Thread-2 tente d'obtenir lock2 sur r2 puis lock1 sur r1. Si les deux obtiennent leurs premiers verroux simultanément, un interblocage se produira.