原创

java面试题-synchronized和ReentrantLock区别是什么?

在Java多线程编程中,保障线程安全是一个重要的问题。synchronizedReentrantLock 是两种常用的锁机制,用于解决多线程环境下的竞争问题。本教程将详细比较这两者的区别,并提供相应的代码示例,使初学者能够深入理解它们的使用方式和特性。

1. synchronized 和 ReentrantLock 的基本区别

1.1 等待锁的方式

  • synchronized: 当线程竞争锁失败时,会一直等待,直到获取到锁。

  • ReentrantLock: 可以尝试获取锁,并得到获取结果,可以通过 tryLock 方法设置等待时间。

1.2 超时设置

  • synchronized: 无法设置获取锁的超时时间。

  • ReentrantLock: 可以设置获取锁的超时时间,避免长时间等待。

1.3 公平性

  • synchronized: 无法实现公平锁,即不能保证等待时间最长的线程最先获取到锁。

  • ReentrantLock: 可以满足公平锁,即先等待的线程先获取到锁。

1.4 控制等待和唤醒

  • synchronized: 需要结合加锁对象的 wait()notify()notifyAll() 方法来控制等待和唤醒。

  • ReentrantLock: 需要结合 Conditionawait()signal()signalAll() 方法来控制等待和唤醒。

1.5 实现方式

  • synchronized: 是JVM层面实现的,是一种隐式锁。

  • ReentrantLock: 是JDK代码层面实现的,是一种显式锁。

1.6 锁的释放

  • synchronized: 在加锁代码块执行完或者出现异常时,自动释放锁。

  • ReentrantLock: 不会自动释放锁,需要在 finally{} 代码块中显式释放。

2. 示例代码演示

2.1 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) {
        SynchronizedExample example = new SynchronizedExample();

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

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

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

2.2 ReentrantLock 示例

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

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

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

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();

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

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

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

3. 代码解释

  • SynchronizedExample 使用 synchronized 关键字来保证线程安全。

  • ReentrantLockExample 使用 ReentrantLock 来保证线程安全,并在 increment 方法中显式地加锁和解锁。

4. 总结

通过本教程,我们深入了解了 synchronizedReentrantLock 的区别和使用方法。在实际开发中,选择合适的锁机制取决于具体的需求,同时要注意锁的释放,以防止死锁等问题的发生。

正文到此结束
本文目录