Lock与synchronized 的区别

#牛客AI配图神器#

Lock 接口和 synchronized 关键字都是 Java 中用于实现线程同步的机制,但它们在功能、灵活性和使用方式上存在一些显著的区别。下面是详细的对比和解释:

synchronized 关键字

定义

synchronized 是 Java 中的一个关键字,用于实现线程同步,确保在同一时间只有一个线程可以访问被同步的代码块或方法。

主要特点

  • 内置机制synchronized 是 Java 语言级别的同步机制,内置在 Java 虚拟机(JVM)中。
  • 自动释放锁:当线程退出同步代码块或方法时,锁会自动释放。
  • 不可中断synchronized 不能被中断,线程必须等待锁的释放。
  • 粒度较粗:只能用于同步方法或代码块,粒度较粗。
  • 非公平锁:默认是非公平锁,即线程获取锁的顺序不确定。
  • 隐式锁:使用 synchronized 时,锁是隐式的,不需要显式地创建和管理锁对象。

示例代码

public class SynchronizedExample {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample example = new SynchronizedExample();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Final count: " + example.getCount());
    }
}

Lock 接口

定义

Lockjava.util.concurrent.locks 包中的一个接口,提供了比 synchronized 更灵活的锁机制。

主要特点

  • 显式锁Lock 是显式的,需要显式地创建和管理锁对象。
  • 可中断Lock 支持可中断锁,线程在等待锁时可以被中断。
  • 公平锁和非公平锁:可以创建公平锁和非公平锁。
  • 粒度更细:可以更灵活地控制锁的获取和释放。
  • 条件变量:提供了 Condition 接口,支持更复杂的线程同步操作。
  • 手动释放锁:必须显式地调用 unlock() 方法释放锁,否则可能导致死锁。

示例代码

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private final Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockExample example = new LockExample();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Final count: " + example.getCount());
    }
}

synchronizedLock 的主要区别

定义

Java 关键字,内置在 JVM 中

java.util.concurrent.locks.Lock

接口

锁的获取

自动获取和释放锁

手动获取和释放锁

中断

不能被中断,线程必须等待锁的释放

可以被中断,线程在等待锁时可以被中断

公平性

默认是非公平锁

可以创建公平锁和非公平锁

粒度

粒度较粗,只能用于同步方法或代码块

粒度更细,可以更灵活地控制锁的获取和释放

条件变量

无条件变量,只能通过

wait()

notify()

方法实现

提供

Condition

接口,支持更复杂的线程同步操作

隐式 vs 显式

隐式锁,不需要显式地创建和管理锁对象

显式锁,需要显式地创建和管理锁对象

性能

在低竞争环境下性能较好,高竞争环境下性能较差

在高竞争环境下性能较好

详细对比

  1. 锁的获取和释放synchronized:自动获取和释放锁,当线程退出同步代码块或方法时,锁会自动释放。Lock:必须显式地调用 lock() 方法获取锁,调用 unlock() 方法释放锁。如果不显式释放锁,可能导致死锁。
  2. 中断synchronized:不能被中断,线程必须等待锁的释放。Lock:支持可中断锁,线程在等待锁时可以被中断,抛出 InterruptedException。
  3. 公平性synchronized:默认是非公平锁,即线程获取锁的顺序不确定。Lock:可以通过构造函数参数指定锁的公平性,例如 new ReentrantLock(true) 创建公平锁。
  4. 粒度synchronized:粒度较粗,只能用于同步方法或代码块。Lock:粒度更细,可以更灵活地控制锁的获取和释放,支持更复杂的同步逻辑。
  5. 条件变量synchronized:通过 Object 类的 wait() 和 notify() 方法实现条件变量。Lock:提供了 Condition 接口,支持更复杂的线程同步操作,可以创建多个条件变量。
  6. 性能synchronized:在低竞争环境下性能较好,但在高竞争环境下性能较差,因为锁的获取和释放开销较大。Lock:在高竞争环境下性能较好,提供了更多的优化选项,如公平锁和非公平锁的选择。

使用场景

  • synchronized 关键字:适用于简单的同步场景,代码简洁。适用于不需要复杂同步逻辑的场景。适用于低竞争环境下的同步需求。
  • Lock 接口:适用于需要更灵活和复杂的同步逻辑的场景。适用于需要中断支持的场景。适用于需要公平锁的场景。适用于需要手动控制锁的获取和释放的场景。

总结

  • synchronized 关键字:内置、自动管理、简单易用,适用于简单的同步需求。
  • Lock 接口:显式管理、更灵活、支持更多高级功能,适用于复杂的同步需求。

选择使用 synchronized 还是 Lock 取决于具体的应用需求和并发控制策略。对于简单的同步需求,synchronized 是一个很好的选择;对于复杂的同步需求,Lock 提供了更多的灵活性和功能。

#java##牛客创作赏金赛#
全部评论

相关推荐

评论
6
2
分享

创作者周榜

更多
牛客网
牛客企业服务