如何使用Java锁?

  • Post category:Java

当多个线程需要共同访问一个共享资源时,由于线程执行的随机性,很容易遇到竞态条件的问题。Java提供了锁机制来解决这一问题,锁可用于在多线程访问共享资源时控制对资源的访问。

在Java中,锁机制可以使用synchronized关键字或java.util.concurrent包中的Lock接口实现。

使用synchronized关键字实现锁

synchronized关键字可以用于方法或块的级别以达到锁的效果。当一个线程访问一个被synchronized关键字保护的代码块时,其他线程会被阻塞,直到该线程完成该代码块的执行。

public class SynchronizedDemo { 
    private int count; 
    public synchronized void increment() { 
        count++; 
    } 
}

在上述例子中,当多个线程访问increment()方法时,只有一个线程可以执行该方法,其他线程将被阻塞。因为synchronized关键字的使用,保证了count++操作的原子性,避免了竞争条件。

使用Lock接口实现锁

Lock接口是一种更灵活的锁,相对于synchronized关键字来说,它提供了更多控制多线程访问共享资源的方式。在使用Lock时,需要调用lock()方法来获取锁,使用完毕后需要调用unlock()方法释放锁。

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

public class LockDemo {
    private Lock lock = new ReentrantLock(); // 创建ReentrantLock锁 

    public void increment() {
        lock.lock(); // 获取锁 
        try { 
            count++; 
        } finally { 
            lock.unlock(); // 释放锁 
        } 
    }
}

在上述例子中,线程需要使用lock()方法获取锁,而不是快捷方式synchronized。并且需要在使用完锁之后调用unlock()方法释放锁,以便其他线程进行访问。

示例

Synchronized锁

下面的示例演示了如何使用synchronized关键字来实现一个线程安全的计数器。

public class SynchronizedCounter {
    private int count = 0;

    public synchronized int increment() {
        count++;
        return count;
    }

    public synchronized int decrement() {
        count--;
        return count;
    }

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

在上述例子中,increment()decrement()getCount()方法都使用synchronized关键字,以便避免多个线程同时对count变量进行读写。

Lock锁

下面的示例演示了如何使用Lock接口来实现一个线程安全的计数器。

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

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

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

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

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

在上述示例中,与synchronized关键字不同,使用Lock锁需要在try-finally代码块中包装获取锁和释放锁的过程。在获取锁失败的情况下,finally中的代码块将负责释放锁。