Java中的两个一样的锁

在多线程编程中,锁是一种用来协调对共享资源访问的机制。Java提供了多种锁的实现方式,其中最常见的是Synchronized关键字和ReentrantLock类。在这篇文章中,我们将讨论“两个一样的锁”这一概念,分析如何在Java中使用它们,以及它们的不同之处。

锁的基本概念

在Java中,锁用于保证在多线程环境下,多个线程不能同时访问某个共享资源。每个锁可以被视作一个“开关”,只有持有该锁的线程可以执行相应的代码。为了更好地理解这一概念,看看下图的类图:

classDiagram
    class Lock {
        +void lock()
        +void unlock()
    }
    class SynchronizedLock {
        +synchronized void method1()
    }
    class ReentrantLock {
        +void lock()
        +void unlock()
    }

    Lock <|-- SynchronizedLock
    Lock <|-- ReentrantLock

Synchronized关键字

Synchronized是Java中最常用的同步方式,它可以用在方法或代码块上。当一个线程访问被synchronized修饰的方法时,其他线程会被阻塞,直到该线程释放锁。

示例代码

public class SynchronizedExample {
    private static int count = 0;

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

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count: " + count);
    }
}

在上述代码中,increment方法是被synchronized修饰的,因此当一个线程在执行这个方法时,另一个线程无法进入。

ReentrantLock类

ReentrantLock是Java提供的一种显示锁,它提供了比synchronized更高级的功能,如尝试锁定、定时锁等。ReentrantLock也允许线程在中断时返回,从而提升了灵活性。

示例代码

import java.util.concurrent.locks.ReentrantLock;

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

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

    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count: " + count);
    }
}

这里使用ReentrantLock实现了与synchronized相同的功能。无论是synchronized还是ReentrantLock,它们的目的都是为了确保对共享资源的安全访问。

结论

在Java中,虽然synchronizedReentrantLock都是用来解决多线程竞争的问题,但它们各有优势。Synchronized易用且简洁,而ReentrantLock则提供了更大的灵活性和功能。在选择使用哪种锁时,开发者需要根据具体情况作出权衡。理解这两者的工作机制和特性,能帮助我们编写更安全、高效的多线程代码。