Разница между синхронизированной блокировкой в ​​этом и классе! | Испытание августовского обновления

Java задняя часть
Разница между синхронизированной блокировкой в ​​этом и классе! | Испытание августовского обновления

Synchronized — распространенный метод решения проблем параллелизма в языке Java, его еще ласково называют «встроенной блокировкой Java», что свидетельствует о его высоком статусе. Тем не менее, синхронизированный имеет множество применений.Когда он изменяет разные объекты, его значение также отличается.Давайте посмотрим на это вместе. ​

синхронизированное использование

синхронизированный можно использовать для измененияОбычные методы, статические методы и блоки кода. ​

① Модификация обычных методов

/**
 * synchronized 修饰普通方法
 */
public synchronized void method() {
    // .......
}

Когда synchronized изменяет общий метод, измененный метод называется синхронизированным методом, его областью действия является весь метод, а объектом действия является объект, вызывающий метод. ​

② Изменить статические методы

/**
 * synchronized 修饰静态方法
 */
public static synchronized void staticMethod() {
    // .......
}

Когда синхронизация изменяет статический метод, его областью действия является весь метод, а область действия — все объекты, вызывающие этот класс.

③ Изменить блок кода

Чтобы уменьшить степень детализации блокировки, мы можем использовать синхронизированный для оформления определенной части метода (блока кода), чтобы заблокировать часть кода в методе.Код реализации выглядит следующим образом:

public void classMethod() throws InterruptedException {
    // 前置代码...
    
    // 加锁代码
    synchronized (SynchronizedExample.class) {
        // ......
    }
    
    // 后置代码...
}

Когда приведенный выше код выполняется, измененный блок кода называется синхронизированным блоком операторов, а его областью действия является блок кода, заключенный в фигурные скобки "{}", а объектом действия является объект, вызывающий этот блок кода. ​

Но приведенный выше код, помимо блокировки класса, также может заблокировать это, конкретный пример выглядит следующим образом:

public void classMethod() throws InterruptedException {
    // 前置处理代码...
    synchronized (this) {
        // ......
    }
    // 后置处理代码...
}

Вопрос в том, в чем разница между использованием synchronized для блокировки этого и класса? Разве они не блокируют один и тот же класс? ​

Ответ на самом деле нет, разница между блокировкой this и class все еще очень велика. Давайте посмотрим на разницу между ними на следующих 4 примерах.

1. Заблокированные классы совместно используют экземпляр класса

Во-первых, мы создаем 5 потоков и вызываем код класса синхронизированной блокировки для одного и того же объекта. Конкретный пример выглядит следующим образом:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // 创建当前类实例
        final SynchronizedExample example = new SynchronizedExample();
        // 创建 5 个线程执行任务
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 调用 synchronized 修饰的 class 方法
                        example.classMethod();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    /**
     * synchronized 修饰的 class 方法
     * @throws InterruptedException
     */
    public void classMethod() throws InterruptedException {
        synchronized (SynchronizedExample.class) {
            System.out.println(String.format("当前执行线程:%s,执行时间:%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

Результат выполнения вышеуказанной программы выглядит следующим образом:image.pngИз приведенных выше результатов видно, что пять потоков используют одну и ту же блокировку.

2. Блокировка класса для создания нескольких экземпляров

Далее мы создаем 5 потоков и вызываем код класса синхронизированной блокировки под разными объектами.Конкретный пример выглядит следующим образом:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // 创建 5 个线程执行任务
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 创建类实例
                        SynchronizedExample example = new SynchronizedExample();
                        // 调用 synchronized 修饰的 class 方法
                        example.classMethod();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    /**
     * synchronized 修饰的 class 方法
     * @throws InterruptedException
     */
    public void classMethod() throws InterruptedException {
        synchronized (SynchronizedExample.class) {
            System.out.println(String.format("当前执行线程:%s,执行时间:%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

Результат выполнения вышеуказанной программы выглядит следующим образом:image.pngКак видно из приведенных выше результатов, хотя это разные объекты, они все равно используют одну и ту же блокировку.

3. Заблокируйте это, чтобы поделиться экземпляром класса

Затем мы создаем 5 потоков и вызываем синхронизацию, чтобы заблокировать этот пример. Сначала наши пять потоков вызывают метод блокировки одного и того же объекта Пример кода выглядит следующим образом:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // 创建当前类实例
        final SynchronizedExample example = new SynchronizedExample();
        // 创建 5 个线程执行任务
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 调用 synchronized 修饰的 this 方法
                        example.thisMethod();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    /**
     * synchronized 修饰的 this 方法
     * @throws InterruptedException
     */
    public void thisMethod() throws InterruptedException {
        synchronized (this) {
            System.out.println(String.format("当前执行线程:%s,执行时间:%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

Результат выполнения вышеуказанной программы выглядит следующим образом:image.pngИз приведенных выше результатов видно, что все вышеперечисленные потоки используют одну и ту же блокировку.

4. Заблокируйте это, чтобы создать несколько экземпляров класса.

Последний пример является самым особенным. Мы используем synchronized, чтобы заблокировать его и позволить этим пяти потокам вызывать свои собственные методы создания объектов. Конкретные примеры приведены ниже:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // 创建 5 个线程执行任务
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 创建(多个)类实例
                        SynchronizedExample example = new SynchronizedExample();
                        // 调用 synchronized 修饰的 this 方法
                        example.thisMethod();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
    
    /**
     * synchronized 修饰的 this 方法
     * @throws InterruptedException
     */
    public void thisMethod() throws InterruptedException {
        synchronized (this) {
            System.out.println(String.format("当前执行线程:%s,执行时间:%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

Результат выполнения вышеуказанной программы выглядит следующим образом:image.pngИз приведенных выше результатов видно, что при использовании synchronized для блокировки этого, если потоки вызывают не один и тот же объект, блокировки, используемые между этими потоками, являются их собственными независимыми блокировками.Этот результат полностью такой же, как результат синхронизированной блокировки класс разные. ​

Суммировать

Из приведенных выше 4 примеров мы можем сделать вывод, что когдаПри использовании синхронизированного класса блокировки независимо от того, используют ли они общий объект или создают несколько объектов, все они используют одну и ту же блокировку.,а такжеПри использовании синхронизированного для блокировки только один и тот же объект будет использовать одну и ту же блокировку, а блокировки между разными объектами будут разными.. ​

Рекомендуемые статьи из этой серии

  1. Параллелизм. Урок 1. Сведения о потоке
  2. В чем разница между пользовательскими потоками и потоками демона в Java?
  3. Глубокое понимание пула потоков ThreadPool
  4. 7 способов создать пул потоков, настоятельно рекомендуется их использовать...
  5. Насколько хороша технология объединения? Я был потрясен, когда увидел сравнение между потоками и пулами потоков!
  6. Синхронизация потоков и блокировки в параллелизме
  7. Разница между volatile и синхронизированным
  8. Обязательно ли легкие замки быстрее, чем тяжелые замки?
  9. Приведет ли завершение потока таким образом к отключению службы?
  10. 5 решений для небезопасного потока SimpleDateFormat!
  11. ThreadLocal не прост в использовании? Ты бесполезен!
  12. Демонстрация кода переполнения памяти ThreadLocal и анализ причин!
  13. Признания Семафора: Я прав с ограничителем тока!
  14. CountDownLatch: Не сомневайтесь, подождите, пока все перегруппируются!
  15. CyclicBarrier: Когда все люди будут готовы, водитель может стартовать!

Подпишитесь на официальный аккаунт «Сообщество китайского языка Java», чтобы увидеть больше интересных и полезных статей о параллельных Java.