1乐观锁 和悲观锁
简绍:
悲观锁是指假设并发更新冲突会发生,所以不管冲突是否真的发生,都会使用锁机制。
相对悲观锁而言,数据库一般采用悲观锁,悲观锁就是 直接上锁,同步方法就属于悲观锁。
乐观锁机制采取了更加宽松的加锁机制,乐观锁采用判断情况 来决定是否上锁
/**
* 秒杀服务
* Created by 51422 on 2017/9/6.
*/
public class MiaoSha {
public static int goods=10;
/**
* 返回订单号
* @return -1 表示无货 否则货号
* @throws InterruptedException
*/
public int getGoods() throws InterruptedException {
//todo 在这里完成获取货物代码
Thread.sleep(100);//处理延时100ms
return -1;
}
}
/**
* 测试案例
*/
public void testMiaoSha(){
final MiaoSha miaoSha=new MiaoSha();
long st=System.currentTimeMillis();
ScheduledExecutorService service = Executors.newScheduledThreadPool(500);
for(int i=0;i<50000;i++){
service.execute(new Runnable() {
public void run() {
try {
int good=miaoSha.getGoods();
if(good>0){
System.out.println("获取到订单"+good);
};
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
service.shutdown();
try {
service.awaitTermination(2, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("耗时"+(System.currentTimeMillis()-st)+"ms");
}
1.1悲观锁处理方式
这种方式虽然能保证货物不会超发,但是不能保证运行速度 所有线程都会变成同步,处理时间会变长。
/**
* 秒杀服务
* Created by 51422 on 2017/9/6.
*/
public class MiaoSha {
public static int goods=10;
/**
* 返回订单号
* @return -1 表示无货 否则货号
* @throws InterruptedException
*/
public int getGoods() throws InterruptedException {
//todo 在这里完成获取货物代码
synchronized(this){
if(goods>0){
int no=goods;
goods--;
Thread.sleep(100);//处理延时100ms
return no;
}
Thread.sleep(100);//处理延时100ms
return -1;
}
}
}
1.2乐观锁处理方式
增加version变量 表示当前货物版本,线程进入的时候获取version, 同当前version对比 如果相同则参加锁竞争 ,竞争获得锁后再次对比version 防止version过期 。如果version还是痛当前版本号相同, 则获取订单,这样只有版本号相同的线程才回产生排队,保证速度的同时 也能保证货物不会被超发。
/**
* 秒杀服务
* Created by 51422 on 2017/9/6.
*/
public class MiaoSha {
public static int goods=10;
public static int version=0;
/**
* 返回订单号
* @return -1 表示无货 否则货号
* @throws InterruptedException
*/
public int getGoods() throws InterruptedException {
//todo 在这里完成获取货物代码
int v=-1;
if(goods>0&&(v=version)>0){
if(v==version){
synchronized(this){
if(v==version){
version++;
int no=goods;
goods--;
Thread.sleep(100);//处理延时100ms
return no;
}
}
}
}
Thread.sleep(100);//处理延时100ms
return -1;
}
}
2.信号量Semaphore
锁能保证同时只有一个线程使用资源 不能让指定个数的线程同时访问资源,
这个时候就需要信号量,可以保证指定个数的线程访问资源,达到限流或者限速,
比如同时只有2个客户端可以连接到服务器并使用。
public static void SamephoreTest(){
Semaphore samephore=new Semaphore(2);
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
samephore.acquire();
System.out.println("我访问了!");
Thread.sleep(5000);//休眠5s
samephore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
- acquire获取许可 是个阻塞的方法
- release释放许可
- acquire和release必须成对出现 否则会产生资源死锁
网友评论