synchronized

举报
赵KK日常技术记录 发表于 2023/07/07 09:48:47 2023/07/07
【摘要】 Synchronized原理是什么? 1. 简介在多线程编程中,为了确保共享资源的安全性,我们需要使用同步机制。其中,synchronized关键字是Java语言提供的一种同步机制,用于保护临界区,防止多个线程同时访问共享资源而出现数据不一致或异常的情况。本文将介绍synchronized关键字的工作原理,并通过示例代码演示其在多线程环境下的使用。 2. synchronized关键字的使...

Synchronized原理是什么?

1. 简介

在多线程编程中,为了确保共享资源的安全性,我们需要使用同步机制。其中,synchronized关键字是Java语言提供的一种同步机制,用于保护临界区,防止多个线程同时访问共享资源而出现数据不一致或异常的情况。

本文将介绍synchronized关键字的工作原理,并通过示例代码演示其在多线程环境下的使用。

2. synchronized关键字的使用

在Java中,我们可以使用synchronized关键字来修饰方法或代码块,以实现同步。其使用形式如下:

  • 同步方法:使用synchronized修饰方法,示例代码如下:
public synchronized void synchronizedMethod() {
    // 临界区代码
    // ...
}
  • 同步代码块:使用synchronized关键字修饰代码块,指定需要同步的对象,示例代码如下:
public void synchronizedBlock() {
    // 非临界区代码
    // ...

    synchronized (object) {
        // 临界区代码
        // ...
    }

    // 非临界区代码
    // ...
}

在上述示例中,synchronizedMethod()方法和synchronizedBlock()方法中的临界区代码将会被同一时刻只允许一个线程执行,其他线程需要等待。

3. synchronized原理

synchronized关键字的原理基于Java对象头和内置锁(Intrinsic Lock)。

3.1 Java对象头

在Java虚拟机中,每个对象都有一个对象头,用于存储对象自身的运行时数据,包括对象的哈希码、锁状态标志等信息。对于被synchronized关键字修饰的方法或代码块,虚拟机会使用对象头中的一部分数据来实现锁的获取与释放。

3.2 内置锁

每个Java对象都可以关联一个内置锁,也称为监视器锁(Monitor Lock)。内置锁是对对象进行加锁和解锁的机制,可以确保在同一时间只有一个线程可以获取到该对象的锁。被加锁的对象只能被加锁线程访问,其他线程必须等待锁的释放。

当一个线程尝试获取一个对象的锁时,如果该锁被其他线程占用,则该线程会被阻塞,直到锁被释放。

3.3 synchronized实现原理

synchronized关键字的实现原理可以分为三种状态:无锁状态、偏向锁状态和重量级锁状态。

  • 无锁状态:如果一个对象没有被任何线程锁定,那么它的对象头中的锁标志位为“无锁状态”。此时,可以通过CAS(Compare and Swap)操作直接获取锁,无需额外的同步操作。

  • 偏向锁状态:第一个获取锁的线程会把对象头中的锁标志位设置为“偏向锁状态”。在偏向锁状态下,如果有其他线程尝试获取锁,会通过CAS操作判断是否可以直接获取锁。如果可以,则进行偏向锁的撤销,否则转为重量级锁状态。

  • 重量级锁状态:如果对象头中的锁标志位为“重量级锁状态”,说明锁已被其他线程占用。此时,获取锁的线程会进入阻塞状态,直到持有锁的线程释放锁。

synchronized关键字的原理是通过对象头中的锁标志位和内置锁来实现线程同步。

4. synchronized的示例代码演示

为了更好地理解synchronized的原理,我们将通过一个示例代码演示其在多线程环境中的使用。

public class SynchronizedDemo {

    private int count = 0;

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();
        demo.start();
    }

    public void start() {
        // 创建两个线程并启动
        Thread thread1 = new Thread(new MyRunnable());
        Thread thread2 = new Thread(new MyRunnable());
        thread1.start();
        thread2.start();

        // 主线程等待两个线程执行完毕
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 输出最终的计数结果
        System.out.println("Count: " + count);
    }

    // 自定义的Runnable实现类
    class MyRunnable implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                // 使用synchronized修饰临界区
                synchronized (this) {
                    count++;
                }
            }
        }
    }
}

在上述示例代码中,我们创建了一个SynchronizedDemo类,其中包含一个count变量。我们创建了两个线程,并分别启动这两个线程。每个线程都会对count变量进行10000次递增操作。由于count是一个共享资源,为了确保多个线程安全地访问它,我们使用了synchronized关键字将临界区代码块进行同步。

运行以上代码,输出的结果应为20000。

5. 总结

本文介绍了synchronized关键字的原理,它是Java多线程编程中常用的同步机制。通过synchronized关键字的修饰,我们可以保护临界区,防止多个线程同时访问共享资源,从而确保线程安全。

synchronized的原理基于Java对象头和内置锁。对象头存储了锁的状态信息,内置锁用于保护对象的临界区。不同状态的锁(无锁状态、偏向锁状态、重量级锁状态)决定了线程获取锁的方式和行为。

虽然synchronized是Java多线程编程中最基本和常用的同步机制,但在高并发场景下,它可能会导致性能下降。因此,在实际开发中,需要根据具体情况选择更适合的同步方式,如使用Lock接口提供的互斥锁。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。