java并发编程使用锁进行数据同步操作一

项目中总是出现招标项目超投的情况,最开始总是觉得应该使用框架Hibernate自带的并发策略中的乐观锁(version)解决问题,参考了很多网上的资料,也参考了Hibernate的帮助文档,由于对Hibernate乐观锁机制不了解,问题就一直没有解决。

最近在看Java并发编程相关知识,了解了些许并发,线程,锁的知识。想到了这个问题,曾经使用Synchroized关键字时总是苦于无法获取同一个对象,导致解决方案无效。这次采用的方案是:创建了静态的HashMap<Integer,Lock>,初始化一定数量的对象(可结合服务器的性能来确认对象的数量),采用公平模式竞争锁,在处理业务数据。

package com;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class testMain {
/**
 * test类
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
testOut testOut=new testOut();
outPut o =new outPut(testOut);
//模拟并发三个线程
new Thread(o,"first").start();
new Thread(o,"second").start();
new Thread(o,"thread").start();
}
}
/**
 * 线程类
 * @author linyan
 *
 */
class outPut implements Runnable{
private testOut testOut;
public outPut(testOut t){
testOut=t;
}
@Override
public void run() {
// TODO Auto-generated method stub
testOut.sysout(20);
}
}
/**
 * 业务处理方法
 * @author linyan
 *
 */
class testOut{
/**
 * 创建静态map
 * 初始化map对象
 */
public final static HashMap<Integer,Lock> map=new HashMap<Integer,Lock>();
static{
for(int i=0;i<2;i++){
//初始化公平锁,确保等待时间最久的线程获得锁
map.put(i, new ReentrantLock(true));
}
}
private int number=0;
public void sysout(int i){
System.out.println(Thread.currentThread().getName()+":"+i);
//模拟同一个招标项目的标的编号来争抢锁
int index=i%map.size();
try{
map.get(index).lock();
//TOOD  业务逻辑处理方法
number=number+i;
//输出当前获得线程的锁及请求参数
System.out.println(Thread.currentThread().getName()+":"+index);
//获得当前线程内查看到的活动线程数
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().activeCount());
//输出对应累加的数值
System.out.println(Thread.currentThread().getName()+"="+number);
}finally{
map.get(index).unlock();
}
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}

对应的输出结果:

thread:20
first:20
first:0
first:4
first=20
second:20
thread:0
thread:3
thread=40
second:0
second:2
second=60

经过反复的测试,输出的结果都和预期一致,故判定这一解决方案有效。将解决方案放到具体项目上实施,结果仍然出现了超投问题,经过问题定位发现,在业务逻辑处理中业务逻辑的事务分割范围太宽,导致了数据不能立即入库,同时Hibernate的查询仍与缓存交互,不是实时查询数据库,导致继续超投的情况。

事务范围切割问题很好解决,但是对Hibernate查询问题一直没有解决,为了解决问题,采用了临时方案:创建JDBC连接来实时查询。最终以牺牲了部分性能为代价,解决这个问题,最近在研究一下Hibernate查询方式,看是否能用Hibernate的实时查询。

时间: 2024-10-12 16:01:16

java并发编程使用锁进行数据同步操作一的相关文章

Java并发编程:锁的释放

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

java并发编程常见锁类型

锁是java并发编程中最重要的同步机制.锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息.锁是解决并发冲突的重要工具.在开发中我们会用到很多类型的锁,每种锁都有其自身的特点和适用范围.需要深刻理解锁的理念和区别,才能正确.合理地使用锁.常用锁类型乐观锁与悲观锁悲观锁对并发冲突持悲观态度,先取锁后访问数据,能够较大程度确保数据安全性.而乐观锁认为数据冲突的概率比较低,可以尽可能多地访问数据,只有在最终提交数据进行持久化时才获取锁.悲观锁总是先获取锁,会增加很多额外的开销,

Java并发编程-各种锁

安全性和活跃度通常相互牵制.我们使用锁来保证线程安全,但是滥用锁可能引起锁顺序死锁.类似地,我们使用线程池和信号量来约束资源的使用, 但是缺不能知晓哪些管辖范围内的活动可能形成的资源死锁.Java应用程序不能从死锁中恢复,所以确保你的设计能够避免死锁出现的先决条件是非常有价值. 一.死锁 经典的"哲学家进餐"问题很好的阐释了死锁.5个哲学家一起出门去吃中餐,他们围坐在一个圆桌边.他们只有五只筷子(不是5双),每两个人中间放有一只. 哲学家边吃边思考,交替进行.每个人都需要获得两只筷子才

Java并发编程:Concurrent锁机制解析

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

转: 【Java并发编程】之二十:并发新特性—Lock锁和条件变量(含代码)

简单使用Lock锁 Java5中引入了新的锁机制--Java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接口有3个实现它的类:ReentrantLock.ReetrantReadWriteLock.ReadLock和ReetrantReadWriteLock.WriteLock,即重入锁.读锁和写锁.lock必须被显式地创建.锁定和释放,为了可以使用更多的功能,一般用ReentrantLock为其实例化

Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

Java并发编程系列[未完]: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) 一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现线程之间的切换这就需要从用户态转换到核心

Java并发编程深入学习——Lock锁

Lock锁介绍 ??在Java 5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile.Java 5.0 增加了一种新的机制:ReentrantLock.它并不是一种替代内置加锁的方法,而是当内置加锁机制不适用时,作为一种可选择的高级功能. Lock接口 Lock接口位于java.util.concurrent.locks包中,它定义了一组抽象的加锁操作. public interface Lock { //获取锁 void lock(); // 如果当

【Java并发编程实战】-----“J.U.C”:CLH队列锁

在前面介绍的几篇博客中总是提到CLH队列,在AQS中CLH队列是维护一组线程的严格按照FIFO的队列.他能够确保无饥饿,严格的先来先服务的公平性.下图是CLH队列节点的示意图: 在CLH队列的节点QNode中包含有一个locked的字段,该字段表示该节点是否需要获取锁,为true表示需要获取,为false表示不需要获取.在CLH队列中,节点与节点之间并不是通过next指针来连接的而是通过myPred所指向节点的变化情况来影响的myNode的行为. 假设有两个线程(线程A.线程B).开始线程A需要

Java并发编程与技术内幕:聊聊锁的技术内幕(上)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 一.基础知识 在Java并发编程里头,锁是一个非常重要的概念.就如同现实生活一样,如果房子上了锁.别人就进不去.Java里头如果一段代码取得了一个锁,其它地方再想去这个锁(或者再执行这个相同的代码)就都得等待锁释放.锁其实分成非常多.比如有互斥锁.读写锁.乐观锁.悲观锁.自旋锁.公平锁.非公平锁等.包括信号量其实都可以认为是一个锁. 1.什么时需要锁呢? 其实非常多的场景,如共享实例变量.共