Синхронизация взаимного исключения Java при использовании и сравнении ключевого слова Synchronized и ReentrantLock

Привыкайте писать вместе! Это 8-й день моего участия в «Новом ежедневном плане Nuggets · Апрельское задание по обновлению», нажмите, чтобы просмотреть подробности мероприятия.

Четыре способа использования ключевого слова synchronized

1. Синхронизируйте блок кода

        public void func1(){
//            同步代码块
            synchronized (this){
               //...
            }
        }
复制代码

Это == работает только с одним и тем же объектом ==, если вы вызовете синхронизированный блок кода для двух объектов, он не будет синхронизирован

Для следующих потоков синхронизация достигается, поскольку вызывается один и тот же объект.

/**
 * @Author 胡孟帆
 * @Date 2021-11-21 15:58
 * @Function
 **/
 @SpringBootTest
public class SynchronizedTests {
    @Test
    void contextLoads() {
    }
	public static void main(String[] args) {
        SynchronizedExample e1 = new SynchronizedExample();
        ExecutorService executorService = Executors.newCachedThreadPool();
//        同一个对象调用
        executorService.execute(() -> e1.func1());
        executorService.execute(() -> e1.func1());
    }
    public static class SynchronizedExample{
        public void func1(){
//            同步代码块
            synchronized (this){
                for (int i = 0;i < 10;i++){
                    System.out.print(i + " ");
                }
            }
        }
    }
}
复制代码

вставьте сюда описание изображения

Как видно из вывода, когда один поток входит в синхронизированный блок, другой поток ждет его завершения перед входом.

Для следующих потоков потоки чередуются из-за вызовов разных объектов.

    public static void main(String[] args) {
        SynchronizedExample e1 = new SynchronizedExample();
        SynchronizedExample e2 = new SynchronizedExample();
//        不同对象调用
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> e1.func1());
        executorService.execute(() -> e1.func1());
    }
复制代码

вставьте сюда описание изображенияПоскольку операция выполняется относительно быстро, здесь она зацикливается 100 раз, а результаты вывода показывают, что два потока выполняются перекрестно.

2. Синхронизируйте метод

//    同步一个方法
    public static class SynchronizedExample{
//        同步方法
        public synchronized void func1(){
            for (int i = 0;i < 100;i++){
                System.out.print(i + " ");
            }
        }
    }
复制代码

вставьте сюда описание изображения

Он действует на один и тот же объект как блок синхронизированного кода, а разные объекты выполняются перекрестно.

3. Синхронизируйте класс

    public void func1(){
        synchronized (SynchronizedExample.class){
			for (int i = 0;i < 10;i++){
                System.out.print(i + " ");
            }
        }
    }
复制代码

вставьте сюда описание изображения

Действует на весь класс, а значит, разные объекты тоже будут синхронизированы

4. Синхронизируйте статический метод

    public static class SynchronizedExample{
//        同步一个静态方法
        public synchronized void func1(){
            for (int i = 0;i < 10;i++){
                System.out.print(i + " ");
            }
        }
    }
复制代码

вставьте сюда описание изображенияВоздействие на весь класс, как синхронизированный блок кода, воздействует на один и тот же объект, а разные объекты выполняются перекрестно.

ReentrantLock

ReentrantLock — это блокировка в пакете java.util.concurrent (JUC).

/**
 * @Author 胡孟帆
 * @Date 2021-11-21 17:06
 * @Function
 **/
public class LockTests {

    public static void main(String[] args) {
        LockTests lockTests = new LockTests();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> lockTests.func());
        executorService.execute(() -> lockTests.func());
    }

//    新建一个ReentrantLock对象
    private Lock lock = new ReentrantLock();

    public void func(){
//        上锁
        lock.lock();
        try {
            for (int i = 0;i < 10; i++){
                System.out.print( i+ " ");
            }
        }finally {
//            确保释放锁,避免发生死锁
            lock.unlock();
        }
    }
}
复制代码

вставьте сюда описание изображения

сравнение двух

1, реализация блокировки

Synchronized реализуется JVM, а ReentrantLock реализуется JDK.

2. Производительность

В новой версии Java реализовано множество оптимизаций для синхронизированных, таких как спин-блокировки и т. д., и производительность между ними сравнима.

3. Ожидание можно прервать

Когда поток, удерживающий блокировку, не освобождает блокировку в течение длительного времени, ожидающий поток может отказаться от ожидания и вместо этого заняться другими делами. ReentrantLock можно прервать, а синхронизировать нельзя.

4. Честный замок

Справедливая блокировка означает, что когда несколько потоков ожидают одной и той же блокировки, они должны получать блокировки в последовательности, соответствующей временной последовательности применения блокировки. Блокировки в synchronzied несправедливы, ReentrantLock тоже несправедлив по умолчанию, но может быть справедливым

5. Замки связывают несколько условий

ReentrantLock может связывать несколько объектов Condition (идентифицированный, большой подонок)

6. Используйте выделение

Если вам не нужно использовать расширенные функции ReentrantLock, == предпочитает использовать synchronized==, потому что synchronized — это механизм блокировки, реализованный JVM, и JVM изначально поддерживает его, в то время как ReentrantLock поддерживается не всеми версиями JDK, и использование синхронизированный Не беспокойтесь о проблемах взаимоблокировки, вызванных не снятием блокировок, потому что JVM сохранит освобождение блокировок

рекомендация

отjuejin.im/post/7084170918309658637