Java Thread synchronized

本文详细介绍了Java中synchronized关键字的使用方式及其背后的锁机制,包括如何通过synchronized修饰方法和代码块来确保共享变量的互斥访问,避免数据不一致问题。同时,文中还讨论了使用synchronized时需要注意的一些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

synchronized关键字提供了一种锁机制,能确保共享变量的互斥访问,防止数据不一致的问题出现。
synchronized其实是获取synchronized修饰的monitor锁。monitor锁包括monitor enter和monitor exit两个JVM指令。将java编译成汇编的时候就会显示地出现这个锁。


使用synchronized可以修饰方法和代码块。
但是有一些注意点:
1. 与monitor锁关联的关键字不能为空

public void syncMethod() {
    synchronized (this) {
        ...
    }
}
  1. synchronized作用域太大
    作用域越大,效率越低。
public class MyThread extends Thread {
    @Override
    public synchronized void run() {
        ...
    }
}
  1. 不同的monitor企图锁相同的方法
public class Task implements Runnable {
    private final Object MUTEX = new Object();
    @Override
    public void run() {
        //...
        synchronized (MUTEX) {
            //...
        }
        //...
    }
    public static void main(String[] args) {
        IntStream.range(0,5).foreach(i -> new Thread(Task::new).start());
    }
}

MUTEX 根本不是同一个对象,起不了互斥作用。
4. 多个锁的交叉导致死锁


This Monitor

This Monitor就是synchronized(this),其实synchronized修饰的对象方法使用的就是This Monitor。下面的代码是等价的:

public synchronized void method() {
    //...
}

public void method() {
    synchronized(this) {
        //...
    }
}
Class Monitor

Class Monitor就是synchronized(xxx.class),synchronized修饰修饰的静态方法就是Class Monitor。下面代码是等价的:

public synchronized static void method() {
    //...
}
public static void method() {
    synchronized(xxxx.class) {
        //...
    }
}

synchronized不能被打断。

### Java中`synchronized`关键字的用法和作用 #### 1. `synchronized`的基本功能 `synchronized`是Java语言中的一个关键字,用于确保线程安全。它通过提供互斥锁、对象锁和类锁、内存可见性以及锁升级等功能,确保了多线程环境下的数据一致性和系统稳定性[^3]。具体来说,`synchronized`可以锁定一个对象或一段代码块,从而保证同一时刻只有一个线程能够访问被锁定的资源。 #### 2. 使用场景 `synchronized`通常用于以下场景: - **共享资源的访问控制**:当多个线程需要访问同一个共享资源时,使用`synchronized`可以防止并发问题。 - **方法级别的同步**:对于需要确保线程安全的方法,可以通过将整个方法声明为`synchronized`来实现。 - **代码块级别的同步**:如果只需要对方法中的某一部分进行同步,可以使用`synchronized`代码块,指定锁对象以减少锁的粒度。 #### 3. 原理分析 `synchronized`的实现原理基于Java内存模型(JMM)中的监视器锁(Monitor)。当一个线程进入`synchronized`修饰的方法或代码块时,它会尝试获取该对象的监视器锁。如果锁已被其他线程持有,则当前线程会被阻塞,直到锁被释放[^1]。 以下是`synchronized`的两种主要使用方式及其原理: ##### (1) 方法级别的同步 当将一个方法声明为`synchronized`时,表示该方法在执行时会自动获取调用对象的锁(如果是静态方法,则获取类的锁)。代码示例如下: ```java public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } ``` 在上述代码中,`increment`和`getCount`方法都被声明为`synchronized`,这意味着同一时间只能有一个线程可以执行这两个方法中的任意一个[^3]。 ##### (2) 代码块级别的同步 如果只需要对方法中的某一部分进行同步,可以使用`synchronized`代码块。这种方式允许开发者显式地指定锁对象,从而减少锁的粒度。代码示例如下: ```java public class SharedResource { private final Object lock = new Object(); private int value = 0; public void updateValue(int newValue) { synchronized (lock) { value = newValue; } } public int getValue() { synchronized (lock) { return value; } } } ``` 在上述代码中,`updateValue`和`getValue`方法中的同步部分都使用了同一个锁对象`lock`,确保在同一时间只有一个线程可以修改或读取`value`变量。 #### 4. 注意事项 - **性能问题**:由于`synchronized`会导致线程阻塞,因此可能会降低程序的性能。在高并发场景下,应尽量减少锁的粒度,或者考虑使用更高效的并发工具(如`ReentrantLock`)。 - **死锁风险**:如果多个线程在获取锁时存在循环依赖,可能会导致死锁。开发时应避免复杂的锁依赖关系[^2]。 - **内存可见性**:`synchronized`不仅提供了互斥锁的功能,还确保了线程之间的内存可见性。即,当一个线程释放锁后,其他线程可以获得最新的共享变量值[^1]。 #### 示例代码 以下是一个完整的示例,展示了如何使用`synchronized`关键字来解决多线程环境下的竞态条件问题: ```java public class BankAccount { private double balance; public BankAccount(double initialBalance) { this.balance = initialBalance; } public synchronized void deposit(double amount) { if (amount > 0) { balance += amount; System.out.println(Thread.currentThread().getName() + " deposited " + amount); } } public synchronized void withdraw(double amount) throws InterruptedException { if (amount > 0 && balance >= amount) { balance -= amount; System.out.println(Thread.currentThread().getName() + " withdrew " + amount); } else { Thread.sleep(1000); // 模拟等待资金 } } public synchronized double getBalance() { return balance; } } public class Main { public static void main(String[] args) { BankAccount account = new BankAccount(1000); Thread t1 = new Thread(() -> { try { account.withdraw(500); } catch (InterruptedException e) { e.printStackTrace(); } }, "Thread-1"); Thread t2 = new Thread(() -> { account.deposit(300); }, "Thread-2"); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final Balance: " + account.getBalance()); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值