并发带来的对象一致性问题

多线程操作带来数据不一致情况分析,简单demo。

public class Object_IS {
    private Student_Object so = new Student_Object("张三", 123);

    public static void main(String[] args) throws InterruptedException {
        Object_IS os = new Object_IS();
        os.test1();

        for (int i = 0; i < 10; i++) {

            Thread thread = new Thread(() -> {
                os.so = new Student_Object("李四", 900);
            });
            thread.start();
//            os.test1();
            os.test2();
            System.out.println("-------------------------------");
        }
    }

    public void test2() throws InterruptedException {

        String name = this.so.getName();
        //为了使问题暴漏,故意睡眠
        Thread.sleep(100);
        Integer code = this.so.getCode();
        System.out.println("name:" + name + "  code: " + code);
    }

    public void test1() {
        //相当于保持快照
        Student_Object so = this.so;
        String name = so.getName();
        Integer code = so.getCode();
        System.out.println("name:" + name + "  code: " + code);
    }
}

class Student_Object {
    private String name;
    private Integer code;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public Student_Object(String name, Integer code) {
        this.name = name;
        this.code = code;
    }

    @Override
    public String toString() {
        return "Student_Object{" + "name='" + name + '\'' + ", code=" + code + '}';
    }

}

代码分析:
首先main方法中创建了Object_IS对象,对象中包含另外一个对象Student_Object (初始值: name = “张三”,code = 123);
在这里插入图片描述
test1() 方法:

 public void test1() {
    //相当于保持快照
     Student_Object so = this.so;
     String name = so.getName();
     Integer code = so.getCode();
     System.out.println("name:" + name + "  code: " + code);
 }

test1中:Student_Object so = this.so; 如蓝线所示,这样即使os中的so发生了变化,也不会影响方法中下面操作该对象的值。
在这里插入图片描述
test2() 方法:
test2中使用的使this.so 获取当前的值,也即永远可以获取最新的值,可能会带来操作对象不一致的情况。如下: 在方法执行完this.so.getName();后,一个线程改变了this.so的“指向”,指向了一个新的对象,再执行this.so.getCode();则获取的是最新对象的值,而不是原有对象的值。

public void test2() throws InterruptedException {
   String name = this.so.getName();
   //为了使问题暴漏,故意睡眠
   Thread.sleep(100);
   Integer code = this.so.getCode();
   System.out.println("name:" + name + "  code: " + code);
}

在这里插入图片描述
按照方法test2()的执行情况,可能会出现(name = “张三”、code = 900)的情况(错误数据)。
执行完 String name = this.so.getName();后,一个线程改变了Object_IS中so的“指向”
,从线1 变为了线2 ,此时就发生了同一个方法内,操作对象不一致的情况。test1()方法不会发生这种情况!

并发操作可能带来数据不一致性,主要包括丢失修改、不可重复读、读“脏”数据等问题。以下是一些解决并发操作带来的数据不一致性的方法。 1. 封锁机制:通过加锁来控制事务的并发访问,保证事务的隔离性和原子性。封锁机制可以通过共享锁和排他锁来控制并发访问,避免出现丢失修改、不可重复读、读“脏”数据等问题。 2. 乐观并发控制(Optimistic Concurrency Control,OCC):通过版本控制的方式来实现并发控制,不需要加锁。当一个事务要修改某个数据对象时,先读取该对象的版本号,然后在提交之前检查该对象的版本号是否发生过变化。如果版本号发生了变化,说明该对象已经被其他事务修改过了,当前事务就需要回滚操作。 3. 多版本并发控制(Multi-Version Concurrency Control,MVCC):通过在数据库中维护多个版本的数据对象来实现并发控制。当一个事务要读取某个数据对象时,读取该对象的最新版本,而当一个事务要修改某个数据对象时,创建该对象的新版本,并将新版本的信息保存在数据库中。 4. 读写分离:将读操作和写操作分别分配给不同的服务器处理,以避免并发访问时的冲突。读写分离可以提高系统的并发性能,并减少数据不一致性问题。 5. 分布式事务:在分布式系统中,多个事务可能同时涉及不同的节点。分布式事务可以通过两阶段提交(Two-Phase Commit,2PC)等机制来保证事务的原子性和隔离性,避免数据不一致性问题。 以上这些方法可以用来解决并发操作带来的数据不一致性问题,每种方法都有其适用的场景和优缺点,需要根据具体情况进行选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值