【并发】并发锁机制-深入理解synchronized(一)

本文探讨了Java中共享内存模型导致的线程安全问题,通过示例展示了线程并发对静态变量自增、自减操作可能产生的竞态条件。文章详细介绍了synchronized的使用,包括同步实例方法、静态方法、this实例对象、类对象和对象实例,以及如何解决线程安全问题。此外,还提到了synchronized的原子性和内在锁的概念,并预告了其底层原理的讨论。
摘要由CSDN通过智能技术生成

【并发】并发锁机制-深入理解synchronized(一)

synchronized 基础篇(使用)

一、Java共享内存模型带来的线程安全问题

1. 代码示例

2. 运行结果

3. 问题分析

4. 临界区(Critical Section)

5. 竞态条件(Race Condition)

二、synchronized 的使用

1. 同步普通(实例)方法

2. 同步静态方法

3. 同步this实例对象

4. 同步类对象

5. 同步对象实例

解决之前的共享问题

遗留问题(高级篇种解释)

下一节——synchronized 高级篇(底层原理)


【并发】并发锁机制-深入理解synchronized(一)

这一篇文章主要介绍synchronized的使用和其底层原理!我将会由浅入深带大家学习synchronized!

synchronized 基础篇(使用)

一、Java共享内存模型带来的线程安全问题

思考: 两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?

1. 代码示例

public class SyncDemo {

    private static int counter = 0;

    public static void increment() {
        counter++;
    }

    public static void decrement() {
        counter--;
    }

    public static void main(String[] args) throws InterruptedException {
        // 线程一
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                increment();
            }
        }, "t1");

        // 线程二
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                decrement();
            }
        }, "t2");
        t1.start();
        t2.start();
        // main线程 要等到t1、t2线程 运行结束后才会终止
        t1.join();
        t2.join();

        System.out.println("counter = " + counter);
    }
}

2. 运行结果

以上的结果可能是正数、负数、零(但是为0,基本是不可能出现的!)

3. 问题分析

Java 中对静态变量自增,自减不是原子操作

我们可以查看 i++ i--(i 为静态变量)的 JVM 字节码指令 

i++的JVM 字节码指令

getstatic i    // 获取静态变量i的值

iconst_1     // 将int常量1压入操作数栈

iadd           // 自增

i--的JVM 字节码指令

getstatic i    // 获取静态变量i的值

iconst_1      // 将int常量1压入操作数栈

isub             // 自减

如果单线程情况下,这些JVM指令顺序执行,(不交错)那肯定是没有问题的。

但是,在多线程下,可能会交错运行

4. 临界区(Critical Section)

一个程序运行多个线程本身是没有问题的!问题出在多个线程访问共享资源

多个线程(只)读共享资源其实也没有问题

在多个线程对共享资源读写操作时发生指令交错,就会出现问题!!!

一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区,其共享资源为临界资源

例如,我们上述的代码中的如下部分: 

//临界资源
private static int counter = 0;

public static void increment() { //临界区
    counter++;
}

public static void decrement() {//临界区
    counter--;
}

5. 竞态条件(Race Condition)

多个线程临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件

为了避免临界区的竞态条件发生,有多种手段可以达到目的:

  • 阻塞式的解决方案:synchronized(本章节重点),Lock
  • 非阻塞式的解决方案:原子变量(Atomic原子类,CAS)

 需要注意的是,在Java中同步和互斥的场景都是使用synchronized实现的!但它们是有区别的!

  • 互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码
  • 同步是由于线程执行的先后、顺序不同、需要一个线程等待其它线程运行到某个点 

二、synchronized 的使用

synchronized 同步块是 Java 提供的一种原子性内置锁,Java 中的每个对象都可以把它当作一个同步锁来使用,这些 Java 内置的使用者看不到的锁被称为内置锁,也叫作监视器锁

大致是有 5种用法

1. 同步普通(实例)方法

public synchronized void method() {
    ...
}

2. 同步静态方法

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

3. 同步this实例对象

synchronized(this) {
    ...
}

4. 同步类对象

synchronized(synchronizedDemo.class){
    ...
}

5. 同步对象实例

String lock = "";
synchronized(lock){
    ...
}

解决之前的共享问题

方法一: 

private static int counter = 0;

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

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

方法二:

private static int counter = 0;
private static String lock = "";

public static void increment() {
    synchronized (lock) {
        counter++;
    }
}

public static void decrement() {
    synchronized (lock) {
        counter--;
    }
}

synchronized 实际是用对象锁保证了临界区内代码的原子性 

遗留问题(高级篇种解释)

同步实例对象和同步类对象有什么区别? 

这5种方式在性能上面是否有差别? 

下一节——synchronized 高级篇(底层原理)

【并发】并发锁机制-深入理解synchronized(二)_面向架构编程的博客-CSDN博客Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit,官方称它为“Mark Word”。对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。32位4字节,64位开启指针压缩或最大堆内存数组长度(只有数组对象有)如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度。https://blog.csdn.net/weixin_43715214/article/details/128628524

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金鳞踏雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值