Java多线程(四):竞态和核心代码(Race Conditions and Critical Sections)

竞态可能会在核心代码中法师。如果某部分代码被多个线程执行,如果线程执行的顺序不一样,结果不一样,那么这块代码可以被称为核心代码

核心代码

举个例子:

public class Counter {

     protected long count = 0;

     public void add(long value){
         this.count = this.count + value;
     }
 }

add()方法便是核心代码
我们先拎清楚,cpu是如何改变count的值的:

  1. cpu将count从主内存中读取到cpu寄存器中;
  2. 修改寄存器中的count的值;
  3. 将寄存器中的count的值写回主内存。

如果ThreadA和ThreadB同时执行以上步骤:

  • ThreadA-1, ThreadA-2
  • ThreadB-1, ThreadB-2
  • ThreadA-3, ThreadB-3

这样会导致ThreadB的值覆盖了ThreadA的值,导致结果不是我们想要的结果。

如何避免竞态

可以使用synchronized或Java的各种锁来避免竞态,这些知识点我们后面再说。

吞吐量

public class TwoSums {
    
    private int sum1 = 0;
    private int sum2 = 0;
    
    public void add(int val1, int val2){
        synchronized(this){
            this.sum1 += val1;   
            this.sum2 += val2;
        }
    }
}

上面的例子中,我们简单的将可能发生竞态的代码块直接加锁,这样子虽然解决了问题,但是由于关键代码块每次只有一条线程能进入,吞吐量变低。
改进方法:

public class TwoSums {
    
    private int sum1 = 0;
    private int sum2 = 0;

    private Integer sum1Lock = new Integer(1);
    private Integer sum2Lock = new Integer(2);

    public void add(int val1, int val2){
        synchronized(this.sum1Lock){
            this.sum1 += val1;   
        }
        synchronized(this.sum2Lock){
            this.sum2 += val2;
        }
    }
}

参考:http://tutorials.jenkov.com/java-concurrency/race-conditions-and-critical-sections.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值