003 ++ --

文章目录

    • [++ --](#++ --)
    • [为了解决这个问题,你可以使用 synchronized 关键字来确保每次只有一个线程可以访问 increment() 方法:](#为了解决这个问题,你可以使用 synchronized 关键字来确保每次只有一个线程可以访问 increment() 方法:)
    • [或者,你也可以使用 AtomicInteger,这是一个线程安全的整数类:](#或者,你也可以使用 AtomicInteger,这是一个线程安全的整数类:)
    • 乐观锁

++ --

在Java中,++ 和 -- 操作符并不是线程安全的。这意味着,如果在多线程环境中直接对这些操作符进行并发操作,可能会导致数据的不一致。

java 复制代码
public class Counter {  
    private int count = 0;  
  
    public void increment() {  
        count++;  
    }  
  
    public int getCount() {  
        return count;  
    }  
}

如果有两个线程同时调用 increment() 方法,并且都读取了 count 的值(比如都是0),然后都对其加1,那么两个线程可能都会将 count 设置为1,而不是期望的2。这就是所谓的竞态条件(Race Condition),它导致了数据的不一致。

为了解决这个问题,你可以使用 synchronized 关键字来确保每次只有一个线程可以访问 increment() 方法:

java 复制代码
public class Counter {  
    private int count = 0;  
  
    public synchronized void increment() {  
        count++;  
    }  
  
    public synchronized int getCount() {  
        return count;  
    }  
}

或者,你也可以使用 AtomicInteger,这是一个线程安全的整数类:

java 复制代码
import java.util.concurrent.atomic.AtomicInteger;  
  
public class Counter {  
    private AtomicInteger count = new AtomicInteger(0);  
  
    public void increment() {  
        count.incrementAndGet();  
    }  
  
    public int getCount() {  
        return count.get();  
    }  
}

在这两种情况下,你都可以确保在多线程环境中对 count 的操作是线程安全的

在Java中,++ 和 -- 操作符本身并不具备线程安全性。线程安全性意味着在并发环境中,对共享数据的操作不会导致数据不一致或其他未定义的行为。++ 和 -- 操作符的不安全性主要源于它们包含多个步骤,这些步骤在多线程环境中可能被其他线程的操作打断,从而导致数据竞争(data race)和竞态条件(race condition)。

具体来说,count++(或 count--)这样的操作实际上包含了三个步骤:

读取 count 的当前值。

对该值进行加1(或减1)操作。

将新值写回到 count。

在单线程环境中,这三个步骤是顺序执行的,因此不会出现问题。但在多线程环境中,如果有多个线程同时执行这些步骤,就可能发生以下情况:

两个线程可能几乎同时读取 count 的值,导致它们获取到相同的初始值。

然后,这两个线程可能都会对这个值进行加1(或减1)操作,并试图将结果写回 count。

最终,count 的值只会增加1(或减少1),而不是期望的增加2(或减少2),因为两个线程的操作互相覆盖了。

这种情况就是典型的竞态条件,它导致了数据的不一致性。

为了解决这个问题,需要确保对 count 的操作是原子的,即这些操作在执行过程中不会被其他线程打断。Java提供了几种方法来实现这一点:

使用 synchronized 关键字来同步方法或代码块,确保在同一时间只有一个线程可以执行这些操作。

使用Java的 java.util.concurrent.atomic 包中的原子类,如 AtomicInteger,这些类提供了线程安全的原子操作。

通过这些方法,可以确保在多线程环境中对共享数据的操作是线程安全的,从而避免数据竞争和竞态条件的发生。

乐观锁

java 复制代码
import java.util.concurrent.atomic.AtomicStampedReference;  
  
public class OptimisticLockCounter {  
    private AtomicStampedReference<Integer> countRef;  
    private static final int INITIAL_VALUE = 0;  
    private static final int INITIAL_STAMP = 0;  
  
    public OptimisticLockCounter() {  
        countRef = new AtomicStampedReference<>(INITIAL_VALUE, INITIAL_STAMP);  
    }  
  
    public boolean increment() {  
        int[] stampHolder = new int[1];  
        Integer oldValue, newValue;  
        do {  
            oldValue = countRef.get(stampHolder); // 获取当前值和邮戳  
            newValue = oldValue + 1; // 计算新值  
            // 尝试在邮戳未更改的情况下设置新值  
        } while (!countRef.compareAndSet(oldValue, newValue, stampHolder[0], stampHolder[0] + 1));  
        return true; // 如果成功更新,则返回true  
    }  
  
    public boolean decrement() {  
        int[] stampHolder = new int[1];  
        Integer oldValue, newValue;  
        do {  
            oldValue = countRef.get(stampHolder); // 获取当前值和邮戳  
            newValue = oldValue - 1; // 计算新值  
            // 尝试在邮戳未更改的情况下设置新值  
        } while (!countRef.compareAndSet(oldValue, newValue, stampHolder[0], stampHolder[0] + 1));  
        return true; // 如果成功更新,则返回true  
    }  
  
    public int getCount() {  
        return countRef.getReference(); // 获取当前计数值  
    }  
  
    // 新增一个尝试获取当前计数值和邮戳的方法,便于测试  
    public int[] getCountAndStamp() {  
        return new int[]{countRef.getReference(), countRef.getStamp()};  
    }  
}
相关推荐
叽哥6 分钟前
Kotlin学习第 1 课:Kotlin 入门准备:搭建学习环境与认知基础
android·java·kotlin
Hy行者勇哥21 分钟前
物联网软件开发过程中,数据流图(DFD),用例图,类图,活动图,序列图,状态图,实体关系图(ERD),BPMN(业务流程建模)详解分析
java·物联网·struts
Miracle65826 分钟前
从 0 到 1 开发校园二手交易系统:飞算 JavaAI 全流程实战
java
A尘埃41 分钟前
Java+Python混合微服务OCR系统设计
java·python·微服务·混合
Seven971 小时前
剑指offer-22、从上往下打印⼆叉树
java
A尘埃1 小时前
企业级Java项目金融应用领域——保险系统(补充)
java·金融·保险系统
冬天vs不冷1 小时前
Java基础(九):Object核心类深度剖析
java·开发语言·python
悟空聊架构2 小时前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
Dajiaonew2 小时前
Spring AI RAG 检索增强 应用
java·人工智能·spring·ai·langchain
IT古董6 小时前
第四章:大模型(LLM)】06.langchain原理-(3)LangChain Prompt 用法
java·人工智能·python