synchronized和ReentrantLock区别

synchronizedReentrantLock是Java中用于实现线程同步的两种方式,它们在实现细节、使用方式和功能特性上有显著的区别。

1. 实现方式

  • synchronized:是Java的关键字,可以修饰方法或代码块,自动管理同步。它是语言级别的特性,简洁且易用。
  • ReentrantLock:是java.util.concurrent.locks包中的一个类,需要显式地创建和使用。它提供了比synchronized更灵活的锁管理。

2. 锁的实现

  • synchronized:属于不可中断的锁,如果一个线程尝试获取锁失败,它会一直等待,直到成功获得锁。
  • ReentrantLock:支持中断,线程尝试获取锁失败后可以选择中断等待。通过lockInterruptibly()方法可以在获取锁过程中响应中断。

3. 尝试获取锁

  • synchronized:没有提供尝试获取锁的机制,线程只有在锁可用时才能获得锁,若锁不可用则会阻塞。
  • ReentrantLock:提供了tryLock()方法,线程可以立即返回是否成功获得锁,如果未获取锁,可以选择继续等待或执行其他任务。

4. 超时获取锁

  • synchronized:不支持超时获取锁。线程一旦进入等待状态,便一直阻塞,直到获得锁。
  • ReentrantLock:支持超时获取锁,可以通过tryLock(long timeout, TimeUnit unit)方法实现,线程可以在指定的时间内等待获取锁,超过超时时间后自动放弃。

5. 公平性

  • synchronized:不支持公平性设置,线程获取锁的顺序是不确定的,可能会出现线程饥饿的情况。
  • ReentrantLock:支持公平锁,可以通过构造函数参数truefalse来选择是否启用公平性。公平锁确保线程按请求锁的顺序获得锁。

6. 条件变量

  • synchronized:通过Object类的wait()notify()notifyAll()方法实现条件变量。synchronized能够方便地实现基于对象的等待/通知机制,但功能相对简单。
  • ReentrantLock:可以结合Condition对象使用,提供更灵活的条件变量支持。Condition支持多个等待队列,能够在多个条件下实现更复杂的同步需求。

7. 锁状态检查

  • synchronized:没有提供检查锁状态的方法,开发者无法直接判断某个锁是否被占用。
  • ReentrantLock:提供了isLocked()isFair()hasQueuedThreads()等方法,可以检查锁的状态、是否公平以及是否有线程在等待锁。

8. 可重入性

  • synchronized:支持可重入性,即同一个线程可以多次获取同一把锁,系统会自动管理锁计数。
  • ReentrantLock:也支持可重入性,允许同一线程多次获得锁。它通过维护锁的获取计数来实现这一特性。

总结:使用场景和优缺点

  • synchronized:适合简化的同步需求,不需要显式的创建和释放锁,适用于锁持有时间较短、没有复杂逻辑的同步场景。

    • 优点:简洁、易用、自动释放锁。
    • 缺点:缺乏灵活性,比如无法响应中断、无法设置公平性等。
  • ReentrantLock:适用于更复杂的同步场景,特别是需要中断支持、尝试获取锁、超时控制和公平性控制的情况。它提供了更多的功能和控制,但也需要更多的代码管理。

    • 优点:灵活、支持中断、超时获取、条件变量等。
    • 缺点:需要显式地释放锁,容易导致死锁等问题。

如何选择?

  • 简单的同步任务:如果只需要简单的同步,推荐使用synchronized,因为它更加简洁。
  • 复杂的同步任务:如果涉及到中断响应、超时机制或公平锁等高级特性,使用ReentrantLock更加合适。

高级特性:条件变量

  • ReentrantLock结合Condition对象可以实现更复杂的同步模型。例如,多个线程可能需要在某些条件下进行等待和通知,这种情况下Condition提供了比wait()notify()更灵活的功能,能够支持多个等待队列、精确的控制条件

你可能感兴趣的:(Java基础知识,java,开发语言,计算机八股)