跳至主要內容

(3)如何使用线程锁


在多线程编程中,线程锁是一个非常重要的工具,用于防止多个线程同时访问共享资源,这种访问可能会导致数据不一致或其他错误。Java 提供了几种不同的锁机制,包括内置的锁(监视器锁)和 java.util.concurrent 包中的显式锁。下面我将介绍如何使用这些锁:

1. 同步方法(Synchronized Methods)

通过在方法声明前添加 synchronized 关键字,可以确保一次只有一个线程能够执行该方法。如果这个方法是实例方法,锁定的是调用该方法的对象;如果是静态方法,锁定的是这个类的 Class 对象。

public class Counter {
    private int count = 0;

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

    public synchronized int getCount() {
        return count;
    }
}

2. 同步块(Synchronized Blocks)

如果只需要对方法中的某个特定部分进行同步,可以使用同步块。同步块允许你指定一个锁对象。

public class Counter {
    private int count = 0;
    private final Object lock = new Object();

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

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

在这个例子中,increment()getCount() 方法中的同步块使用同一个锁对象 lock。这意味着同时只有一个线程可以执行这两个同步块中的任何一个。

3. 显式锁(Reentrant Lock)

java.util.concurrent.locks.ReentrantLock 是一个实现了 Lock 接口的显式锁。它提供了比内置锁更多的功能和更大的灵活性。

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

public class Counter {
    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();
        }
    }
}

4. 读写锁(Read/Write Lock)

如果你的应用程序涉及到多个线程频繁读取但较少写入数据的场景,使用读写锁(ReentrantReadWriteLock)可能更适合。这种锁允许多个线程同时读取数据,但写入数据时需要独占访问。

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Counter {
    private int count = 0;
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();

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

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

使用锁时需要注意的是,确保在获取锁之后,无论通过哪条路径退出,都要释放锁。这通常通过使用 try-finally 块来实现,如上述示例所示。

总之,选择合适的锁策略和类型是很重要的,这取决于你的应用程序的具体需求。正确使用锁可以有效地减少线程间的冲突,提高程序的性能和可靠性。

上次编辑于: