gtxyzz

请问在不加锁的情况下如何保证线程安全?

gtxyzz 安全防护 2022-11-28 369浏览 0

概念

compare and swap,解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

请问在不加锁的情况下如何保证线程安全?

简单点来说就是修改之前先做一下对比,校验数据是否被其他线程修改过,如果修改过了,那么将内存中新的值取出在与内存中的进行对比,直到相等,然后再做修改。

假如我们要对变量:num做累加操作,num初始值=0。1.cpu前往内存取出num;2.判断内存中的num是否被修改;3.做+1操作;4.将修改后的值写入内存中;

请问在不加锁的情况下如何保证线程安全?

这时候可能会有疑问了,判断、自加、写回内存难道不会发生线程安全问题吗?既然cas能成为并发编程中安全问题的解决这,那么这个问题肯定是不会发生的,为什么呢?因为判断、自加、写回内存这是一个由硬件保证的原子操作,硬件是如何保证原子性的,请先看下面这个例子

需求:

使用三个线程分别对某个成员变量累加10W,打印累加结果。

我们使用两种方法完成此需求。1.正常累加(既不加锁,也不使用原子类)。

1.使用synchronized。

2.使用原子类(Atomic)。

实现

1.正常累加(既不加锁,也不使用原子类)。

这种方式没有什么说的,直接上代码

packagecom.ymy.test;


publicclassCASTest{

privatestaticlongcount=0;

/**
*累加10w
*/
privatestaticvoidadd(){

for(inti=0;i<100000;++i){
count+=1;
}

}

publicstaticvoidmain(String[]args)throwsInterruptedException{
//开启三个线程t1t2t3
Threadt1=newThread(()->{
add();
});

Threadt2=newThread(()->{
add();
});

Threadt3=newThread(()->{
add();
});
longstarTime=System.currentTimeMillis();
//启动三个线程
t1.start();
t2.start();
t3.start();
//让线程同步
t1.join();
t2.join();
t3.join();
longendTime=System.currentTimeMillis();
System.out.println("累加完成,count:"+count);
System.out.println("耗时:"+(endTime-starTime)+"ms");
}
}

执行结果

请问在不加锁的情况下如何保证线程安全?

很明显,三个线程累加,由于cpu缓存的存在,导致结果远远小于30w,这个也是我们预期到的,所以才会出现后面两种解决方案。

2.使用synchronized

使用synchronized时需要注意,需求要求我们三个线程分别累加10W,所以synchronized锁定的内容就非常重要了,要么直接锁定类,要么三个线程使用同一把锁,关于synchronized的介绍以及锁定内容请

继续浏览有关 安全 的文章
发表评论