Java锁代码解析

1. 数据竞争导致数据不一致

两个线程分别把一个变量增加10000次,理论上变量最后的值是20000,实际上小于20000

package org.example;

public class synchronizedTest {
    private static int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        // 线程 1:对 counter 进行 10000 次自增操作
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter++;
            }
        });

        // 线程 2:对 counter 进行 10000 次自增操作
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter++;
            }
        });

        // 启动两个线程
        thread1.start();
        thread2.start();

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

        // 预期结果应该是 20000,但由于数据竞争,实际结果可能小于 20000
        System.out.println("Counter value: " + counter);
    }
}

counter++ 的底层操作

counter++ 这个操作在 Java 代码里看似是一个简单的自增操作,但在计算机底层,它实际上是由多个步骤组成的:

  1. 读取(Read):从内存中读取 counter 的当前值到 CPU 的寄存器中。
  2. 加 1(Increment):在寄存器中对读取的值进行加 1 操作。
  3. 写入(Write):将寄存器中加 1 后的值写回到内存中的 counter 变量。

执行过程

  1. 线程 1 读取 counter 的值:线程 1 从内存中读取 counter 的值 0 到它的寄存器中。此时线程 1 的寄存器中的值为 0,内存中 counter 的值仍为 0。
  2. 线程调度切换到线程 2:操作系统将 CPU 控制权交给线程 2。
  3. 线程 2 读取 counter 的值:线程 2 从内存中读取 counter 的值 0 到它的寄存器中。此时线程 2 的寄存器中的值为 0,内存中 counter 的值还是 0。
  4. 线程 2 完成自增并写入:线程 2 在寄存器中对值进行加 1 操作,寄存器中的值变为 1,然后将 1 写回到内存中。此时内存中 counter 的值变为 1。
  5. 线程调度切换回线程 1:操作系统将 CPU 控制权交回给线程 1。
  6. 线程 1 完成自增并写入:线程 1 在它的寄存器中对之前读取的 0 进行加 1 操作,寄存器中的值变为 1,然后将 1 写回到内存中。此时内存中 counter 的值还是 1。

在上述过程中,线程 1 和线程 2 都进行了一次自增操作,但由于数据竞争,内存中 counter 的值只增加了 1,而不是预期的 2,这就导致了数据不一致。

修改后,把修改数据的值操作封装为方法用synchronized修饰,或者用synchronized修饰代码块,确保同一时间只有一个线程能够访问方法

package org.example;

public class synchronizedTest {
    private static int counter = 0;
    private static final Object staticLock = new Object();
    public static synchronized void increment() {
        counter++;
    }
    public static void increment() {
        // 对当前对象(this)加锁
        synchronized (staticLock) {
            counter++;
        }
    }


    public static void main(String[] args) throws InterruptedException {
        // 线程 1:对 counter 进行 10000 次自增操作
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                increment();
            }
        });

        // 线程 2:对 counter 进行 10000 次自增操作
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                increment();
            }
        });

        // 启动两个线程
        thread1.start();
        thread2.start();

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

        // 预期结果应该是 20000,但由于数据竞争,实际结果可能小于 20000
        System.out.println("Counter value: " + counter);
    }
}

2,并发修改

线程1在迭代List的同时,线程2添加新元素

package org.example;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class synchronizedTest {
    public static void main(String[] args) {
        // 创建一个 ArrayList
        List<Integer> list = new ArrayList<>();
        for (int i &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值