关于synchronized的介绍

这篇具有很好参考价值的文章主要介绍了关于synchronized的介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

我们先来看一下什么是synchronized,我做出了以下解释,大家可以看一下.
1.synchronized 是Java中的关键字,用于实现同步机制,确保在多线程环境下对共享资源的访问的安全性。
2.synchronized 可以被用来修饰方法或代码块,其作用是在同一时刻,只能有一个线程执行被 synchronized 修饰的代码,其他线程必须等待锁的释放才能继续执行。

3.在使用 synchronized 时,需要指定锁对象,锁对象可以是任意对象,只有持有同一把锁的线程才能访问被 synchronized 修饰的代码块或方法。

4.当一个线程进入被 synchronized 修饰的代码块或方法时,它会尝试获取锁对象的锁,如果锁没有被其他线程持有,那么该线程会获得锁并继续执行代码,当线程退出 synchronized 修饰的代码块或方法时,它会释放锁,以便其他线程可以获取锁并执行代码。如果锁被其他线程持有,则该线程将进入阻塞状态,等待获取锁。


一.synchronized的特性

我这里开始列出synchronized的特性如下:

原子性:synchronized能够保证被它修饰的代码块或方法的执行是原子性的,即在同一时刻只能有一个线程进入被synchronized修饰的代码块或方法。

可重入性:synchronized是可重入的,即在一个线程已经持有某个对象的锁时,它可以再次进入一个synchronized块或方法。

可见性:synchronized能够保证共享变量在多线程间的可见性,即一个线程修改了共享变量的值,另一个线程能够立即看到该变量的最新值。

互斥性:synchronized能够保证同一时刻只有一个线程能够进入被synchronized修饰的代码块或方法,从而保证线程之间的互斥性。

有序性:synchronized能够保证同一时刻只有一个线程能够执行被synchronized修饰的代码块或方法,从而保证线程之间的有序性。


二.synchronized的使用

我先给出一个综合的代码实例,来基础的展示一下synchronized的使用,代码如下:
这个代码我们就是用加锁操作,来保证俩个线程对count++的操作是原子性的.

public class SynchronizedExample {

    private int count = 0;

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

    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample example = new SynchronizedExample();

        // 创建两个线程来同时增加计数器的值
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                example.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                example.increment();
            }
        });

        thread1.start();
        thread2.start();

        // 等待两个线程执行完毕
        thread1.join();
        thread2.join();

        System.out.println("Count: " + example.count);
    }
}

2.1 同步方法

public class Counter {
    private int count;

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

    public synchronized void decrement() {
        count--;
    }

    public synchronized int getCount() {
        return count;
    }
}

2.2 同步代码块

public class Example {
    private Object lock = new Object();
    private int count = 0;

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

    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

2.3 静态同步方法

public class Example {
    private static int count;

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

    public static synchronized void decrement() {
        count--;
    }

    public static synchronized int getCount() {
        return count;
    }
}

2.4 同步代码块和volatile关键字

public class Example {
    private volatile int count = 0;

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

    public void decrement() {
        synchronized (this) {
            count--;
        }
    }

    public int getCount() {
        return count;
    }
}

这里我简单的介绍了synchronized的使用方法,但synchronized并不是一个单独的个体,可以根据不同场景,综合使用.


三.synchronized的锁机制

synchronized的锁机制,我先简单的阐述一下,什么是锁机制.
锁机制通过对共享资源的加锁来保证同一时刻只有一个线程可以访问该资源,其他线程必须等待锁的释放后才能访问。通过锁机制,可以有效地避免竞态条件的出现,从而保证程序的正确性和稳定性。

对于synchronized的来说,synchronized使用的是对象级别的锁机制,即每个对象都有一个与之关联的锁(也称为监视器)。在synchronized关键字加锁的代码块执行期间,该对象的锁被获取,其他线程无法访问该对象的synchronized代码块,只能等待当前线程执行完毕释放锁之后才能访问。

3.1 synchronized是什么锁机制

synchronized是Java中的一种锁机制,用于控制多个线程对共享资源的访问。synchronized可以用来修饰方法或代码块,在修饰方法时,锁住的是整个方法,而在修饰代码块时,锁住的是代码块中的对象。

synchronized锁机制的实现基于Java中的内置锁,也称为监视器锁。每个Java对象都有一个内置锁,可以用来同步访问该对象的代码。当一个线程获取了一个对象的内置锁后,其他线程必须等待该线程释放锁才能获取该对象的锁。

3.2 synchronized的工作过程

结合我们学习的锁策略,我们对synchronized进行以下总结:

  1. 开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁.
  2. 开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.
  3. 实现轻量级锁的时候大概率用到的自旋锁策略
  4. 是一种不公平锁
  5. 是一种可重入锁
  6. 不是读写锁

加锁过程

关于synchronized的介绍

这上面解释了,synchronized的加锁过程,其中自旋锁和重量级锁,我们都知道是什么,但对偏向锁,好像没有太多的概念,我这里先解释一下什么是偏向锁.
这里还会来举一个生活中的小例子.女神和男神的故事
关于synchronized的介绍

偏向锁,只是先让线程针对锁,有个标记(做个标记很快的,非常轻量)
(偏向锁,只是先让线程针对锁,有个标记(做个标记很快的,非常轻量)

如果整个代码执行过程中,都没有遇到别的线程和我竞争这个锁,此时就不用真加锁了!!!
如果整个代码执行过程中,都没有遇到别的线程和我竞争这个锁~~此时就不用真加锁了!

但是一旦,要是有别的线程尝试来竞争这个锁!!!于是偏向锁就立即升级成真的锁(轻量级锁),此时别的线程只能等待
但是一旦,要是有别的线程尝试来竞争这个锁!于是偏向锁就立即升级成真的锁(轻量级锁),此时别的线程只能等待.
既保证了效率,又保证了线程安全!!
既保证了效率,又保证了线程安全!!

如果还没有明白,我这里再举一个实际的代码例子

public class MyObject {
    private int x;
    private int y;

    public synchronized void increment() {
        x++;
        y++;
    }
}

如果在多线程环境下,多个线程同时对 obj 进行操作,那么就可能会发生竞争条件,从而导致结果不可预测。此时,我们可以使用偏向锁来优化。

偏向锁的实现方式是,如果一个线程获取了该对象的锁,那么该对象就会被标记为偏向模式,并且该线程的 ID 会被记录在对象头中。接下来,如果该线程再次请求锁,就无需进行竞争,直接获取锁即可。这样就可以避免多线程竞争的开销。

例如,我们可以在一个单线程环境下进行如下操作:

MyObject obj = new MyObject();
obj.increment(); // 偏向锁对象
obj.increment(); // 无需竞争,直接获取锁

在第二次调用 increment() 方法时,由于只有一个线程在操作该对象,因此可以直接获取锁,无需进行竞争。这样就可以提高程序的性能

然后我们继续来说明synchronized工作过程的下一个阶段,就是进入偏向锁,之后,随着其他线程进入竞争, 偏向锁状态被消除, 进入轻量级锁状态(自适应的自旋锁).
此处的轻量级锁就是通过 CAS 来实现.

通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)
如果更新成功, 则认为加锁成功
如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU).

最后,如果竞争进一步激烈, 自旋不能快速获取到锁状态, 就会膨胀为重量级锁
此处的重量级锁就是指用到内核提供的 mutex .
执行加锁操作, 先进入内核态.
在内核态判定当前锁是否已经被占用
如果该锁没有占用, 则加锁成功, 并切换回用户态.
如果该锁被占用, 则加锁失败. 此时线程进入锁的等待队列, 挂起. 等待被操作系统唤醒.
经历了一系列的沧海桑田, 这个锁被其他线程释放了, 操作系统也想起了这个挂起的线程, 于是唤醒
这个线程, 尝试重新获取锁.

四. 其他的优化过程

锁消除

简单来说就是非必要不加锁
举一个简单的例子,我们经常使用的StringBuilder和StringBuffer
一般来说,我们说StirngBuffer是线程安全的,为什么呢?大家可以看一下源码
关于synchronized的介绍
这里实际上对他们都进行了加锁,但说实话,我们在使用他们的时候,不一定都是多线程的一个环境,如果是单线程使用,就不涉及线程安全的问题了,但这个但是这个synchronized是不是也写了?,但其实在编译阶段,没有被真正的去编译,这样的操作就是锁消除,可见编译器的优化,很重要,它还是比我们聪明的.
最后来总结一下:
锁消除是指在编译期间,由于分析程序的执行情况发现一些同步操作不会出现竞争,编译器会自动消除这些不必要的同步操作,从而提高程序的执行效率。

锁粗化

画一个小小的图,大家来感受一下:

关于synchronized的介绍
大家如果还是模模糊糊,我来一个实际的代码,大家来体验一下:
例如,下面的代码中,循环内部的加锁和解锁操作会重复执行多次


for (int i = 0; i < 1000; i++) {
    lock();
    // do something
    unlock();
}

如果将这些加锁解锁操作合并为一次加锁解锁操作,代码如下所示:

lock();
for (int i = 0; i < 1000; i++) {
    // do something
}
unlock();

这样做可以减少加锁解锁的次数,从而提高程序的执行效率。

最后来小小的总结一下:
锁粗化是一种优化技术,它的目的是将多个连续的加锁、解锁操作合并成一个更大的锁操作,从而减少加锁解锁的次数,减小锁的竞争。文章来源地址https://www.toymoban.com/news/detail-410833.html

到了这里,关于关于synchronized的介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 最近台风肆虐,让我们用Python获取天气数据,分析一下台风到底要去哪!

    最近台风肆虐,已进入我国24小时警戒线!台风“卡努”到底要去哪儿? 作为一个Python程序员,虽然我帮不上忙,但是时时关注一下还是可以的,顺便祈祷一下台风往东边某个小日子过得不错的小岛吹。 于是我花了一分钟,用Python写了一个获取天气数据的代码,然后进行数据

    2024年02月14日
    浏览(42)
  • WebGL前言——WebGL相关介绍

    第一讲内容主要介绍WebGL技术和相应的硬件基础部分,在初级课程和中级课程的基础上,将技术和硬件基础进行串联,能够对WebGL从产生到消亡有深刻全面的理解。同时还介绍WebGL大家在初级课程和中级课程中的一些常见错误以及错误调试的办法。 先热身一下吧,看个问题:如

    2023年04月08日
    浏览(44)
  • 【RabbitMQ教程】前言 —— 中间件介绍

                                                                       💧 【 R a b b i t M Q 教程】前言——中间件介绍 color{#FF1493}{【RabbitMQ教程】前言 —— 中间件介绍} 【 R abbi tMQ 教程】前言 —— 中间件介绍 💧           🌷 仰望天空,妳

    2024年02月08日
    浏览(69)
  • synchronized的介绍

    synchronized是Java编程语言中的一个,用于实现线程同步。在多线程编程中,多个线程可能同时访问共享资源,而这可能导致数据不一致或其他问题。为了避免这些问题,可以使用 synchronized 来确保在任何时候只有一个线程可以访问共享资源。 使用synchronized就是为了

    2024年01月25日
    浏览(28)
  • Rx.NET in Action 中文介绍 前言及序言

    目标 可选方式 Rx 处理器(Operator) 创建 Observable Creating Observables 直接创建 By explicit logic Create Defer 根据范围创建 By specification Range Repeat Generate Timer Interval Return 使用预设 Predefined primitives Throw Never Empty 从其他类型创建 From other types FromEventPattern FromEvent FromTask FromAsync 变换 Transform

    2024年02月13日
    浏览(48)
  • 微信小程序-关于我们页面模板

    JS WXML WXSS

    2024年02月16日
    浏览(53)
  • 关于GPT4,我们都知道什么?

    人工智能原理与实践 全面涵盖人工智能和数据科学各个重要体系经典 北大出版社,人工智能原理与实践 人工智能和数据科学从入门到精通 详解机器学习深度学习算法原理 我们生活在一个AI激动人心的时代,你会不停看到各种新型模型的推出,它们彻底改变了 AI 领域。2022

    2023年04月16日
    浏览(39)
  • 关于Copilot一直登录不上(试一下学校内网吧)

    请移步此帖子↓ 已更新方法(二): http://t.csdn.cn/Drgks 无需其他软件,设置编辑器内代理即可 本帖子这个设置校园网可能有的人用不了,可以看看新帖子的 先说一下结论,如果你理解我在说什么,可以直接开始操作: 1.用 你们学校的VPN教程(每个大学应该都有) 2. 连上你

    2024年02月09日
    浏览(42)
  • 我们所知道的关于 OpenAI 的 ChatGPT 的一切

    如果您还没有听说过ChatGPT,这是来自人工智能实验室 OpenAI 的不可思议的新聊天机器人,这里是您需要了解的有关这个有争议的新程序的所有信息的快速入门。 ChatGPT 是一种人工智能工具,允许用户生成原始文本。你可以问它问题,给它创造性的提示,并用它来生成一大堆不

    2023年04月13日
    浏览(40)
  • 关于npoi插入一条斜向上得线记录一下

    在使用hssf可以直接按照行列插入。  但是呢,在使用XSSF得时候,使用同样方式得写法就不生效了,根据chatgpt给出的答案。  我也不知道这个答案是否准确,但是我接纳他的建议,画一条斜向下得线,然后垂直翻转过来。  

    2024年02月13日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包