java学习的时候有碰到关于多线程修改共享变量的问题,典型的案例就是抢车票或者是电站商品库存业务场景下,java提解决这种问题的方案就是提供了synchronzied关键字 去控制同一时间内只有一个线程在访问并修改数据.也就是同步锁(也叫排它锁)。说到synchronzied关键字自然就会想到2种用法:同步函数及同步代码快的方式.以前只知道同步代码块相比同步函数因为作用范围更小,所以效率上更高.同步函数只需要在方法的修饰词前面加上synchronzied关键字即可.而关于同步代码块只了解synchronized(Object对象),通过这个对象去控制同一时间访问这个对象的线程去控制数据溢出的问题.
同步函数与同步代码块用法上的差别
- 同步函数使用在函数或者方法上,通过方法前面添加修饰词的方式使普通函数成功同步函数.
- 而同步代码块一般是在普通函数内添加一段synchronzied控制的代码以达到同步排他的作用.可以使用this关键字或者直接使用一个任意对象去控制。如果使用this关键字实际上同步代码快与同步函数之间就没啥差别了.而如果是同步代码块如果使用的其他对象的话,控制的内容就不同乐.
典型案例:使用this关键字修饰的同步代码块与同步函数没有区别的证明
SynObjy.class(包含一个同步函数+this关键字的同步代码块+任意对象控制的同步代码快)
public class SynObjy {
//测试同步函数锁与同步代码块锁之间的区别
public synchronized void methodA() {
System.out.println("methodA......");
try {
for (int i = 1; i <= 5; i++) {
Thread.sleep(1000);
System.out.println("线程休眠:"+i);
}
} catch (Exception ex) {
// TODO: handle exception
}
}
//同步代码块函数
public void methodB() {
synchronized (this) {
System.out.println("methodB......");
}
}
//同步代码块使用任意对象锁
public void methodC(){
String string="sss";
synchronized(string){
System.out.println("methodC....");
}
}
}
TestSyn.class
public class TestSyn {
public static void main(String[] args) {
final SynObjy synObjy=new SynObjy();
//模拟同步函数方法thisA
Thread thread=new Thread(new Runnable() {
public void run() {
synObjy.methodA();
}
});
//模拟同步代码块方法thisB
Thread thread2=new Thread(new Runnable() {
public void run() {
synObjy.methodB();
}
});
//模拟object同步代码块方法C
Thread thread3=new Thread(new Runnable() {
public void run() {
synObjy.methodC();
}
});
thread.start();
thread2.start();
thread3.start();
}
}
执行结果:
methodA......
methodC....
线程休眠:1
线程休眠:2
线程休眠:3
线程休眠:4
线程休眠:5
methodB......
总结
从上面可以看出3个线程同时运行,方法A采用的是同步函数的方式与方法C同步代码块的锁对象不同,所以可以同时执行.而方法B因为同步代码块使用的this关键字,所以实际上与方法A的锁对象相同,所以方法B会等方法A线程休眠完毕才会执行.另外因为同步代码块因为影像的范围小所以效率更高,如果在系统吞吐性能要求不高的情况,选择synchornzied关键字 同步函数的方式无疑是个的选择.
联想
之前做微信小程序商品购买支付成功会有一个微信异步回调 去修改商品库存信息,但同时会购买成功 需要弹出一个购买结果的页面(如果商品购买结果不是支付成功就去查询支付结果并修改商品库存).这样2个线程之间就会出现线程竞争同一个资源的问题,可能在微信异步通知的时候微信,另一个微信支付结果主动查询也同时在进行操作导致出现问题. 利用同步代码块this关键字能够很好的实现同一个对象中多个线程竞争统一资源的问题.如果是在不同对象控制层中控制共享资源的解决方式 可以创建一个公共对象 用以实现多线程资源竞争问题.
还有一种解决方式就是2个线程同时 进入则通过唯一索引表添加 订单编号信息,前面的线程进去了,添加记录到唯一索引表里面.而后面的线程由于唯一索引表已经存在了,所以就不能直接插入数据了.