MST

星途 面试题库

面试题:Java中ReentrantLock与Synchronized在使用场景上有何不同

请阐述在Java中,ReentrantLock与Synchronized通常分别适用于哪些类型的场景,并举例说明原因。
16.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

ReentrantLock适用场景

  1. 需要更灵活的锁控制场景:例如在复杂的同步控制逻辑中,需要实现锁的可中断获取、锁的公平性等功能。比如一个多线程任务调度系统,部分任务可能因为优先级高,希望在等待锁时可以中断等待去执行更紧急的任务。
import java.util.concurrent.locks.ReentrantLock;

public class TaskScheduler {
    private static final ReentrantLock lock = new ReentrantLock();

    public static void highPriorityTask() {
        boolean gotLock = false;
        try {
            // 可中断地获取锁
            gotLock = lock.tryLock();
            if (gotLock) {
                // 执行高优先级任务
                System.out.println("执行高优先级任务");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("高优先级任务获取锁中断");
        } finally {
            if (gotLock) {
                lock.unlock();
            }
        }
    }
}
  1. 需要精确控制锁的粒度场景:在一些数据结构实现中,可能需要对不同部分进行更细粒度的锁控制。以实现一个支持并发操作的链表为例,可能需要对链表头、链表尾分别加锁。
import java.util.concurrent.locks.ReentrantLock;

public class ConcurrentLinkedList {
    private Node head;
    private Node tail;
    private final ReentrantLock headLock = new ReentrantLock();
    private final ReentrantLock tailLock = new ReentrantLock();

    public void addToHead(Object value) {
        headLock.lock();
        try {
            Node newNode = new Node(value);
            newNode.next = head;
            head = newNode;
            if (tail == null) {
                tail = head;
            }
        } finally {
            headLock.unlock();
        }
    }

    public void addToTail(Object value) {
        tailLock.lock();
        try {
            Node newNode = new Node(value);
            if (tail == null) {
                head = tail = newNode;
            } else {
                tail.next = newNode;
                tail = newNode;
            }
        } finally {
            tailLock.unlock();
        }
    }

    private static class Node {
        Object value;
        Node next;

        Node(Object value) {
            this.value = value;
        }
    }
}

Synchronized适用场景

  1. 简单同步场景:当同步代码块或方法逻辑较为简单,对锁的功能需求不复杂时,使用synchronized非常方便。例如在一个简单的计数器类中。
public class SimpleCounter {
    private int count = 0;

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

    public synchronized int getCount() {
        return count;
    }
}
  1. 基于对象或类的同步场景:当需要基于对象实例或者类进行同步时,synchronized能自然地满足需求。例如一个单例模式的实现,确保只有一个实例被创建。
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}