当前位置: 面试刷题>> synchronized 关键字是什么,有什么作用?


在Java编程领域,synchronized 关键字是并发编程中不可或缺的一部分,它扮演着确保线程安全的重要角色。作为一名高级程序员,深入理解 synchronized 的工作原理、应用场景及其限制,对于编写高效、稳定的多线程程序至关重要。

synchronized 关键字是什么?

synchronized 是Java提供的一种内置锁机制,用于控制多个线程对共享资源的访问。当一个线程访问某个对象的某个 synchronized 方法或代码块时,它会获得该对象的锁,其他线程在尝试访问该对象的同步方法或代码块时将被阻塞,直到锁被释放。这种机制有效地防止了多线程环境下的数据不一致性问题。

作用与优势

  1. 互斥性:确保同一时刻只有一个线程能够执行某个对象的同步方法或代码块,从而保护共享数据不被并发修改导致的数据不一致。

  2. 可见性synchronized 还能保证一个线程对共享变量的修改,对于之后进入同一个锁的另一个线程是可见的。这是通过“内存屏障”(Memory Barrier)机制实现的,确保线程间的数据通信正确性。

  3. 可重入性:Java中的 synchronized 锁是可重入的,意味着同一个线程可以多次获得同一个锁。这避免了死锁的风险,使得锁的使用更加灵活。

示例代码

下面是一个使用 synchronized 关键字保证线程安全的简单例子。假设我们有一个银行账户类,需要确保在多线程环境下余额的修改是安全的。

public class BankAccount {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    // 使用 synchronized 修饰方法,确保线程安全
    public synchronized void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println(Thread.currentThread().getName() + " Deposited: " + amount);
            System.out.println("New balance is: " + balance);
        }
    }

    // 另一个同步方法
    public synchronized void withdraw(double amount) {
        if (amount > 0 && balance >= amount) {
            balance -= amount;
            System.out.println(Thread.currentThread().getName() + " Withdrew: " + amount);
            System.out.println("New balance is: " + balance);
        } else {
            System.out.println("Insufficient funds");
        }
    }

    // 主函数,用于测试
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);

        Thread t1 = new Thread(() -> account.withdraw(800));
        Thread t2 = new Thread(() -> account.deposit(500));

        t1.start();
        t2.start();

        // 等待两个线程执行完成
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述示例中,depositwithdraw 方法都被 synchronized 修饰,这意味着在任何时刻,只有一个线程可以执行这两个方法中的任何一个。这保证了即使多个线程同时操作账户,账户的余额也不会因为并发修改而出错。

注意事项与进阶

虽然 synchronized 提供了一种简单有效的线程同步机制,但它也有其局限性,比如可能会导致线程饥饿、死锁等问题,并且在高并发场景下性能可能不够理想。作为高级程序员,还需要了解其他并发工具,如 ReentrantLockSemaphoreCountDownLatch 等,以及Java并发包 java.util.concurrent 中的高级并发工具,以便根据具体场景选择最合适的并发解决方案。

此外,synchronized 锁默认是锁定当前实例对象(对于实例方法)或Class对象(对于静态方法)。了解这一点对于深入理解Java的锁机制以及解决复杂的并发问题至关重要。

在持续学习与实践的过程中,不断深化对 synchronized 关键字及其相关并发工具的理解,并结合码小课等优质资源,能够显著提升解决复杂并发问题的能力,从而编写出更加高效、稳定的Java程序。

推荐面试题