常见的Java锁有哪些?

  • Post category:Java

下面是关于“常见的Java锁有哪些?”的完整使用攻略。

一、Java锁的分类

Java锁分为两类:悲观锁和乐观锁。

1. 悲观锁

悲观锁是一种独占锁,它假设任何时候都有可能有其它线程来竞争锁,在竞争锁时会使用synchronized或ReentrantLock等可重入锁来保证只有一个线程可以执行临界区代码。

1.1 synchronized

synchronized是Java中最常见的锁,它可以用来修饰方法或代码块。它只能在同一时刻允许一个线程对临界区代码进行访问。当一个线程正在访问同步代码块时,另一个线程想要进入同步代码块则必须等待。synchronized关键字通常比较适合于小的同步代码块的场景,其优点是使用方便,并且具有可重入性 和适用范围广。

1.2 ReentrantLock

ReentrantLock是一种悲观锁,它支持可重入锁,也支持公平锁和非公平锁。它的优点在于更灵活,可以使用tryLock()方法来避免因为某些事情阻塞线程。

2. 乐观锁

乐观锁假设任意时刻都没有其它线程来竞争锁,所以可以直接进行操作。但是在操作的过程中,如果发现实际上是存在其它线程的竞争,则需要进行一些回退操作,重新尝试。

2.1 CAS

CAS(Compare-And-Swap)是一种无锁算法,它自旋尝试更新数据,直到成功为止,可以解决一些高并发场景,同时避免了线程上下文切换的开销。

二、Java锁的选择

当需要选择使用Java锁时,首先需要根据业务场景和性能需求选择悲观锁或乐观锁。在选择具体的锁实现时,需要根据实际情况来选择。

  • 如果是对简单同步块进行同步控制,则可以使用synchronized。
  • 如果需要更细粒度的同步控制,则使用ReentrantLock。
  • 如果需要更高的性能,可以考虑使用乐观锁,并使用CAS算法。

三、示例说明

下面通过两个简单的示例说明Java锁的用法。

1. 使用synchronized同步代码块

public class SynchronizedDemo {
    private int count = 0;

    public int getCount() {
        return count;
    }

    public void addCount() {
        synchronized (this) {
            count++;
        }
    }
}

上面的代码演示了如何使用synchronized来进行简单线程安全的同步控制,这里使用了同步方法块对count属性进行了同步控制。这样就可以保证在同一时间只有一个线程可以访问count属性。

2. 使用ReentrantLock同步

public class ReentrantLockDemo {
    private ReentrantLock lock = new ReentrantLock();
    private int count = 0;

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

    public int getCount() {
        return count;
    }
}

上面的代码演示了如何使用ReentrantLock来进行线程安全的同步控制,这里使用了lock()和unlock()方法对count属性进行了同步控制。这样就可以保证在同一时间只有一个线程可以访问count属性。相对于synchronized,ReentrantLock支持可重入锁和更灵活的控制。

以上就是关于“常见的Java锁有哪些?”的详细使用攻略。