synchronized 控制访问
springboot现在都是原子事务控制访问
对资源加上控制对象,在一个线程访问时,其他线程只能等待。因为那个锁对象只能由一个占用,第二个线程来时找不到。
1: 可创建任意对象
2:多个线程使用统一锁对象
第一种直接synchronized
public class runable implments Runable{
private int ticket=20; //定义20个票
Object obj =new Object(); //创建锁对象
@override
public void run(){ //实现卖票逻辑
while(true){
Synchronized(obj) { //!!!同步实现,传入锁对象,并将访问公用对象的代码放入其中
if(ticket>0){ //先判断有无票
try{ Thread.sleep(1000); //睡1s等程序跑一会
}catch(in e){ sys(e);
}
ticket--; //票数减一
}
}
}
}
}
//第二种使用synchronized 修饰的方法,可以实现多个线程的调用。在run(){}中调用check()
public synchronized void check(){
if(ticket>0){ //先判断有无票
try{ Thread.sleep(1000); //睡1s等程序跑一会
}catch(in e){ sys(e);
}
ticket--; //票数减一
}
}
main{ //通过实现Runable接口,创建多线程
Runable ru=new Runable();
Thread t1=new Thread(ru);
Thread t2=new Thread(ru);
Thread t3=new Thread(ru);
t1.start();
t2.start();
t3.start();
}
加锁之后的程序,如果出现异常那么锁会被释放,其他线程就能执行了。
锁又分为偏向锁(假装加锁,其实没有,因为就这一个线程),自旋锁(一个线程占用,其他线程在资源周围打转,试探,最多循环10次,还没有获得锁的话就会变成重量级锁),重量级锁(os去进入等待队列,申请资源)
volatile
线程可见,在一个线程中修改完之后,能反馈到其他线程中。
class T{
bool flag =true;
public void test(){
while(true){
sout("flag为true")
}
}
}
main函数
T t= new T();
new Thread(t::test ,"t1线程").start();
try{
t.sleep(1000);
}catch(InteruptException e){
e.printStackTrace()
}
t.flag=false;
//此时,设置flag的值t线程不会停止。需要在flag前加上volatile使其所有人可见才行。
java提供的automic包有intteger
CAS(乐观锁)操作:cas(地址,期的望值,要改为什么),cas(地址,10,12)我要看到它是10,才进去将它改为12,如果有人先行一步,我就不进去。会产生ABA问题(线程1取钱,线程2取钱,线程3存钱,1先运行,二卡住了,三紧随1运行,原来100,1取了50,3加了50,此时钱成100了,可是2旧期望值是100,本该紧随1执行,然后执行失败,可是3先执行了,导致2执行通过,造成失误),防止这个问题加上版本号。